Added SPU2Ghz to the repository

git-svn-id: http://pcsx2-playground.googlecode.com/svn/trunk@192 a6443dda-0b58-4228-96e9-037be469359c
This commit is contained in:
ramapcsx2 2008-10-12 17:29:15 +00:00 committed by Gregory Hainaut
parent 09cf85f57d
commit 14d14ec6b9
115 changed files with 32342 additions and 0 deletions

View File

@ -0,0 +1,154 @@
#
# CHANGELOG
#
# [+] Added Feature
# [*] Modified Feature
# [-] Removed Feature
# [!] Other
#
# Dates are in D/M/Y format
26/05/2008 - v0.1.9
[+] Added Timestretching feature. Added part of the SoundTouch library files.
[+] Added Winamp DSP plugin support.
[+] Added Limiter toggle key (defaults to [Numpad -]
[*] Completely replaced the sound buffering system in the output modules with a centralized one.
[*] Fixed a few bugs in the savestates: Now the savestats can be used (and seem to work).
[*] Some changes to the mixer.
[-] Removed FMod output. Didn't give any improvement over DSound or XAudio2 and added lad.
[*] Updated config dialog to reflect some of the previous changes.
[!] Updated the copyright notices in each file.
26/05/2008 - v0.1.8
[*] Improved the mixer (gives better volumes in many games)
[*] Coded a working volume fading emulation
[*] Somewhat better AC3 code, which still doesn't work yet anyway.
[*] Improved DPL2 dematrixing.
[*] Many other changes I don't really remember.
[!] It might be a good idea to reset the settings (delete the .ini).
09/01/2008 - v0.1.7
[-] SPU2replay disabled until I add options for it.
[+] Improved the limiter handling to reduce lag (in dsound stereo and 5.1 only).
[+] Initial AC3 decoding - does NOT work yet!
[+] Experimental 24/32bit audio input. This allows the CDDA player in the bios to work!
[+] Added a button on the config to configure the output modules.
NOTE: None of the modules have a config dialog yet.
[*] Simplified redundant code in the mixer.
[*] New experimental register handling method. Might slightly improve the processing speed.
09/01/2008 - SPU2replay alpha 1
[+] Added SPU2replay feature.
How does it work:
1. Play a game using the plugin (it doesn't matter what output mode or audio settings you use).
The plugin will dump ALL the write events in the game, until the emulator is closed.
This is a alpha version and doesn't come with option to start or stop the dumping, it always dumps.
2. In a cmd window, navigate to the pcsx2 folder and run:
rundll32 plugins\spu2ghz.dll,SPU2replay replay_dump.s2r
Alternatively, you can set .s2r files to open with "rundll32 plugins\spu2ghz.dll,SPU2replay %1"
3. Wait for it to finish.
This alpha version doesn't have a dialog for it yet, so there is no way to stop the replay until it finishes.
NOTE: The replay feature saves the events as they happened in the specific session it was run,
it's recommended to avoid playing a replay file with a different version of the plugin,
in case something changed.
02/01/2008 - v0.1.6
[*] Converted all the output modules into C++ classes, this way it's easier to manage them.
[*] Cleaned up some parts of the code.
[*] Modified the DPLII decoding code to try to improve the quality.
[+] Added an option to change the LFE lowpass crossover frequency.
[+] Added "delayed" Irq calls so they are only called once in each T.
[*] Restored the older decoding function, and partially rewrote it.
The newer decoder function was breaking some games.
01/01/2008 - WIP2
[+] Updated the 5.1 module to include experimental ProLogic II decoding (it should give better surround).
[*] Changed the buffer sizing so that the configured buffer size applies to whole samples.
This means now settings 1024 as the buffer size will make it 2048 on stereo output, and 6144 on 5.1 output.
31/12/2007 - WIP
[+] Added a highly experimental Dolby ProLogic decoding (upmixes stereo output into 5.1) output module.
30/12/2007 - v0.1.5
[*] Changed the way the ATTR register is handled. Should fix a lot of games, but it's experimental.
[*] Changed the thread priority of the output modules to TIME_CRITICAL, so that they have the highest possible priority.
[*] Updated to latest and final version of FMod 3.
[*] Changed some parts of register-based (PIO) memory writes to speed up audio streaming writes in RotTK games.
[+] Added DirectSound output module. It seems to work better than all the other modules so I set it as the new default.
[+] Added setting of IRQ reason flags. I didn't even know that register existed!
[+] Added a new ADPCM decoder based on the old one, but with full-block decoding to try to make it a bit faster.
[-] If running with an older emulator build, the CoreReset feature is executed immediately, without a delay.
This fixes booting problems in bios and many games that were broken since this feature was introduced.
30/12/2007 - v0.1.4
[-] completely removed the remains of the "async mixer" mode. It was meaningless without threading, and didn't work.
[*] Fixed the waveOut output module.
[*] Fixed a bug where the ASIO output system was using the defaulf ASIO device sample rate,
regardless of the config value.
[*] Changed the min. buffer size allowed in the config dialog to 512 isntead of 2400.
NOTE 1: Sizes too small can increase the CPU usage and might cause audio problems.
NOTE 2: FMOD and waveOut have this limit increased to 2048.
[*] Changed some code handling voice looping. I don't know if it will fix or break anything.
[+] Added partial support for log levels to the register logging system, to remove the basic
channel attributes from the log files (makes logs more readable and less bloated).
[+] Added experimental XAudio2 output module. Seems to sound well.
[+] Added a hidden option to change the AutoDMA sample rate for each core.
Useful only in some games where the FMVs hang.
[+] Added a check to the Effects processor to avoid crashes when the effects start address is
after the effects end address.
[+] Added /delayload:fmod.dll switch to the linker, so the fmod dll is only needed while
using the fmod output module.
28/12/2007 - v0.1.3
[*] Fixed the sync in pre-svn265 pcsx2 builds. Might help with some games.
27/12/2007 - v0.1.2
[*] Fixed the speed limit dialog setting (it wasn't being handled correctly).
[*] Changed the way I handle AutoDMA transfers:
For some reason the data for core 1 was being replaced with 0s,
so I added a separate temporary buffer to store the data chunks.
This fixes many FMVs with stuttering audio.
[-] Commented out some lines that were changing the ATTR register.
I don't know if this will break anything, but none of the games I tried worked worse.
[-] Removed a BAD hack that was breaking thigns instead of fixing.
26/12/2007 - v0.1.1
[*] Increased the volume shift for the AutoDMA'd audio by 2 (makes the FMVs louder).
[+] Experimental implementation of "core reset" handling.
[+] Added a setting to the config dialog to enable/disable the limiter.
[+] Added a setting to the config dialog to enable/disable all console prints at once.
[+] Uncommented the AutoDMA transfer message prints as they can now be toggled from the config dialog.
[+] Added "Public Release" build option that automatically creates the release package.
25/12/2007 - v0.1.0
[!] First Public release
[!] Too many changes to remember.
I promise to list the changes for every release from now on.
30/04/2007
[+] New feature: Added configuration option "Speed_Limit_Mode" to change the speed limiting algorithm.
Values:
0. No limiter
1. Soft limiter -- less cpu-intensive, but can cause problems
2. Hard limiter -- more cpu-intensive while limiting, but should give better (constant) speeds
NOTE: Only implemented in the FMOD output module.
29/04/2007
[-] Hack: Removed a hack where I was ignoring any KeyOn with ADSR values set to 0.
[-] Hack: Removed a hack in the ADMA detection code. This could break some games.
[*] Bugfix: ENDX wasn't being set/cleared correctly. Thanks pSXAuthor for telling me the way it actually works.
[*] Bugfix: Fixed a bug in the adpcm streaming where I was overwriting the active (playing) block with new data.
This caused clicks in the audio, and desyncs.
[!] Any other changes I forgot.
before 29/04/2007
[!] I wiped the two old changes in the changelog, dated back from 2003.
I will try to update this a bit more.
There have been way too many changes in the last 4 years to remember everything.

503
plugins/spu2ghz/LGPL.txt Normal file
View File

@ -0,0 +1,503 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
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 and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, 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 library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete 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 distribute a copy of this License along with the
Library.
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 Library or any portion
of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
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 Library, 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 Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you 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.
If distribution of 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 satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be 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.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library 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.
9. 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 Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
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 with
this License.
11. 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 Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library 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 Library.
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.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library 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.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser 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 Library
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 Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
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
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. 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 LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@ -0,0 +1,17 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//

863
plugins/spu2ghz/PS2Edefs.h Normal file
View File

@ -0,0 +1,863 @@
#ifndef __PS2EDEFS_H__
#define __PS2EDEFS_H__
/*
* PS2E Definitions v0.6.2 (beta)
*
* Author: linuzappz@hotmail.com
* shadowpcsx2@yahoo.gr
* florinsasu@hotmail.com
*/
/*
Notes:
* Since this is still beta things may change.
* OSflags:
__LINUX__ (linux OS)
_WIN32 (win32 OS)
* common return values (for ie. GSinit):
0 - success
-1 - error
* reserved keys:
F1 to F10 are reserved for the emulator
* plugins should NOT change the current
working directory.
(on win32, add flag OFN_NOCHANGEDIR for
GetOpenFileName)
*/
#include "PS2Etypes.h"
#ifdef __LINUX__
#define CALLBACK
#else
#include <windows.h>
#endif
/* common defines */
#ifndef C_ASSERT
#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
#endif
#if defined(GSdefs) || defined(PADdefs) || defined(SIOdefs) || \
defined(SPU2defs) || defined(CDVDdefs) || defined(DEV9defs) || \
defined(USBdefs) || defined(FWdefs)
#define COMMONdefs
#endif
// PS2EgetLibType returns (may be OR'd)
#define PS2E_LT_GS 0x01
#define PS2E_LT_PAD 0x02 // -=[ OBSOLETE ]=-
#define PS2E_LT_SPU2 0x04
#define PS2E_LT_CDVD 0x08
#define PS2E_LT_DEV9 0x10
#define PS2E_LT_USB 0x20
#define PS2E_LT_FW 0x40
#define PS2E_LT_SIO 0x80
// PS2EgetLibVersion2 (high 16 bits)
#define PS2E_GS_VERSION 0x0006
#define PS2E_PAD_VERSION 0x0002 // -=[ OBSOLETE ]=-
#define PS2E_SPU2_VERSION 0x0005
#define PS2E_CDVD_VERSION 0x0005
#define PS2E_DEV9_VERSION 0x0003
#define PS2E_USB_VERSION 0x0003
#define PS2E_FW_VERSION 0x0002
#define PS2E_SIO_VERSION 0x0001
#ifdef COMMONdefs
u32 CALLBACK PS2EgetLibType(void);
u32 CALLBACK PS2EgetLibVersion2(u32 type);
char* CALLBACK PS2EgetLibName(void);
#endif
// key values:
/* key values must be OS dependant:
win32: the VK_XXX will be used (WinUser)
linux: the XK_XXX will be used (XFree86)
*/
// event values:
#define KEYPRESS 1
#define KEYRELEASE 2
typedef struct {
u32 key;
u32 event;
} keyEvent;
// for 64bit compilers
typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1];
// plugin types
#define SIO_TYPE_PAD 0x00000001
#define SIO_TYPE_MTAP 0x00000004
#define SIO_TYPE_RM 0x00000040
#define SIO_TYPE_MC 0x00000100
typedef int (CALLBACK * SIOchangeSlotCB)(int slot);
typedef struct {
u8 ctrl:4; // control and mode bits
u8 mode:4; // control and mode bits
u8 trackNum; // current track number (1 to 99)
u8 trackIndex; // current index within track (0 to 99)
u8 trackM; // current minute location on the disc (BCD encoded)
u8 trackS; // current sector location on the disc (BCD encoded)
u8 trackF; // current frame location on the disc (BCD encoded)
u8 pad; // unused
u8 discM; // current minute offset from first track (BCD encoded)
u8 discS; // current sector offset from first track (BCD encoded)
u8 discF; // current frame offset from first track (BCD encoded)
} cdvdSubQ;
typedef struct { // NOT bcd coded
u32 lsn;
u8 type;
} cdvdTD;
typedef struct {
u8 strack; //number of the first track (usually 1)
u8 etrack; //number of the last track
} cdvdTN;
// CDVDreadTrack mode values:
#define CDVD_MODE_2352 0 // full 2352 bytes
#define CDVD_MODE_2340 1 // skip sync (12) bytes
#define CDVD_MODE_2328 2 // skip sync+head+sub (24) bytes
#define CDVD_MODE_2048 3 // skip sync+head+sub (24) bytes
#define CDVD_MODE_2368 4 // full 2352 bytes + 16 subq
// CDVDgetDiskType returns:
#define CDVD_TYPE_ILLEGAL 0xff // Illegal Disc
#define CDVD_TYPE_DVDV 0xfe // DVD Video
#define CDVD_TYPE_CDDA 0xfd // Audio CD
#define CDVD_TYPE_PS2DVD 0x14 // PS2 DVD
#define CDVD_TYPE_PS2CDDA 0x13 // PS2 CD (with audio)
#define CDVD_TYPE_PS2CD 0x12 // PS2 CD
#define CDVD_TYPE_PSCDDA 0x11 // PS CD (with audio)
#define CDVD_TYPE_PSCD 0x10 // PS CD
#define CDVD_TYPE_UNKNOWN 0x05 // Unknown
#define CDVD_TYPE_DETCTDVDD 0x04 // Detecting Dvd Dual Sided
#define CDVD_TYPE_DETCTDVDS 0x03 // Detecting Dvd Single Sided
#define CDVD_TYPE_DETCTCD 0x02 // Detecting Cd
#define CDVD_TYPE_DETCT 0x01 // Detecting
#define CDVD_TYPE_NODISC 0x00 // No Disc
// CDVDgetTrayStatus returns:
#define CDVD_TRAY_CLOSE 0x00
#define CDVD_TRAY_OPEN 0x01
// cdvdTD.type (track types for cds)
#define CDVD_AUDIO_TRACK 0x01
#define CDVD_MODE1_TRACK 0x41
#define CDVD_MODE2_TRACK 0x61
#define CDVD_AUDIO_MASK 0x00
#define CDVD_DATA_MASK 0x40
// CDROM_DATA_TRACK 0x04 //do not enable this! (from linux kernel)
typedef void (*DEV9callback)(int cycles);
typedef int (*DEV9handler)(void);
typedef void (*USBcallback)(int cycles);
typedef int (*USBhandler)(void);
// freeze modes:
#define FREEZE_LOAD 0
#define FREEZE_SAVE 1
#define FREEZE_SIZE 2
typedef struct {
char name[8];
void *common;
} GSdriverInfo;
#ifdef _WIN32
typedef struct { // unsupported values must be set to zero
HWND hWnd;
HMENU hMenu;
HWND hStatusWnd;
} winInfo;
#endif
/* GS plugin API */
// if this file is included with this define
// the next api will not be skipped by the compiler
#ifdef GSdefs
// basic funcs
s32 CALLBACK GSinit();
s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread);
void CALLBACK GSclose();
void CALLBACK GSshutdown();
void CALLBACK GSvsync(int field);
void CALLBACK GSgifTransfer1(u32 *pMem, u32 addr);
void CALLBACK GSgifTransfer2(u32 *pMem, u32 size);
void CALLBACK GSgifTransfer3(u32 *pMem, u32 size);
void CALLBACK GSgetLastTag(u64* ptag); // returns the last tag processed (64 bits)
void CALLBACK GSgifSoftReset(u32 mask);
void CALLBACK GSreadFIFO(u64 *mem);
void CALLBACK GSreadFIFO2(u64 *mem, int qwc);
// extended funcs
// GSkeyEvent gets called when there is a keyEvent from the PAD plugin
void CALLBACK GSkeyEvent(keyEvent *ev);
void CALLBACK GSchangeSaveState(int, const char* filename);
void CALLBACK GSmakeSnapshot(char *path);
void CALLBACK GSmakeSnapshot2(char *pathname, int* snapdone, int savejpg);
void CALLBACK GSirqCallback(void (*callback)());
void CALLBACK GSprintf(int timeout, char *fmt, ...);
void CALLBACK GSsetBaseMem(void*);
void CALLBACK GSsetGameCRC(int crc, int gameoptions);
// controls frame skipping in the GS, if this routine isn't present, frame skipping won't be done
void CALLBACK GSsetFrameSkip(int frameskip);
// if start is 1, starts recording spu2 data, else stops
// returns a non zero value if successful
// for now, pData is not used
int CALLBACK GSsetupRecording(int start, void* pData);
void CALLBACK GSreset();
void CALLBACK GSwriteCSR(u32 value);
void CALLBACK GSgetDriverInfo(GSdriverInfo *info);
#ifdef _WIN32
s32 CALLBACK GSsetWindowInfo(winInfo *info);
#endif
s32 CALLBACK GSfreeze(int mode, freezeData *data);
void CALLBACK GSconfigure();
void CALLBACK GSabout();
s32 CALLBACK GStest();
#endif
/* PAD plugin API -=[ OBSOLETE ]=- */
// if this file is included with this define
// the next api will not be skipped by the compiler
#ifdef PADdefs
// basic funcs
s32 CALLBACK PADinit(u32 flags);
s32 CALLBACK PADopen(void *pDsp);
void CALLBACK PADclose();
void CALLBACK PADshutdown();
// PADkeyEvent is called every vsync (return NULL if no event)
keyEvent* CALLBACK PADkeyEvent();
u8 CALLBACK PADstartPoll(int pad);
u8 CALLBACK PADpoll(u8 value);
// returns: 1 if supported pad1
// 2 if supported pad2
// 3 if both are supported
u32 CALLBACK PADquery();
// call to give a hint to the PAD plugin to query for the keyboard state. A
// good plugin will query the OS for keyboard state ONLY in this function.
// This function is necessary when multithreading because otherwise
// the PAD plugin can get into deadlocks with the thread that really owns
// the window (and input). Note that PADupdate can be called from a different
// thread than the other functions, so mutex or other multithreading primitives
// have to be added to maintain data integrity.
void CALLBACK PADupdate(int pad);
// extended funcs
void CALLBACK PADgsDriverInfo(GSdriverInfo *info);
void CALLBACK PADconfigure();
void CALLBACK PADabout();
s32 CALLBACK PADtest();
#endif
/* SIO plugin API */
// if this file is included with this define
// the next api will not be skipped by the compiler
#ifdef SIOdefs
// basic funcs
s32 CALLBACK SIOinit(u32 port, u32 slot, SIOchangeSlotCB f);
s32 CALLBACK SIOopen(void *pDsp);
void CALLBACK SIOclose();
void CALLBACK SIOshutdown();
u8 CALLBACK SIOstartPoll(u8 value);
u8 CALLBACK SIOpoll(u8 value);
// returns: SIO_TYPE_{PAD,MTAP,RM,MC}
u32 CALLBACK SIOquery();
// extended funcs
void CALLBACK SIOconfigure();
void CALLBACK SIOabout();
s32 CALLBACK SIOtest();
#endif
/* SPU2 plugin API */
// if this file is included with this define
// the next api will not be skipped by the compiler
#ifdef SPU2defs
// basic funcs
s32 CALLBACK SPU2init();
s32 CALLBACK SPU2open(void *pDsp);
void CALLBACK SPU2close();
void CALLBACK SPU2shutdown();
void CALLBACK SPU2write(u32 mem, u16 value);
u16 CALLBACK SPU2read(u32 mem);
void CALLBACK SPU2readDMA4Mem(u16 *pMem, u32 size);
void CALLBACK SPU2writeDMA4Mem(u16 *pMem, u32 size);
void CALLBACK SPU2interruptDMA4();
void CALLBACK SPU2readDMA7Mem(u16* pMem, u32 size);
void CALLBACK SPU2writeDMA7Mem(u16 *pMem, u32 size);
// all addresses passed by dma will be pointers to the array starting at baseaddr
// This function is necessary to successfully save and reload the spu2 state
void CALLBACK SPU2setDMABaseAddr(uptr baseaddr);
void CALLBACK SPU2interruptDMA7();
u32 CALLBACK SPU2ReadMemAddr(int core);
void CALLBACK SPU2WriteMemAddr(int core,u32 value);
void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)());
// extended funcs
// if start is 1, starts recording spu2 data, else stops
// returns a non zero value if successful
// for now, pData is not used
int CALLBACK SPU2setupRecording(int start, void* pData);
void CALLBACK SPU2setClockPtr(u32* ptr);
void CALLBACK SPU2async(u32 cycles);
s32 CALLBACK SPU2freeze(int mode, freezeData *data);
void CALLBACK SPU2configure();
void CALLBACK SPU2about();
s32 CALLBACK SPU2test();
#endif
/* CDVD plugin API */
// if this file is included with this define
// the next api will not be skipped by the compiler
#ifdef CDVDdefs
// basic funcs
s32 CALLBACK CDVDinit();
s32 CALLBACK CDVDopen(const char* pTitleFilename);
void CALLBACK CDVDclose();
void CALLBACK CDVDshutdown();
s32 CALLBACK CDVDreadTrack(u32 lsn, int mode);
// return can be NULL (for async modes)
u8* CALLBACK CDVDgetBuffer();
s32 CALLBACK CDVDreadSubQ(u32 lsn, cdvdSubQ* subq);//read subq from disc (only cds have subq data)
s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); //disk information
s32 CALLBACK CDVDgetTD(u8 Track, cdvdTD *Buffer); //track info: min,sec,frame,type
s32 CALLBACK CDVDgetTOC(void* toc); //gets ps2 style toc from disc
s32 CALLBACK CDVDgetDiskType(); //CDVD_TYPE_xxxx
s32 CALLBACK CDVDgetTrayStatus(); //CDVD_TRAY_xxxx
s32 CALLBACK CDVDctrlTrayOpen(); //open disc tray
s32 CALLBACK CDVDctrlTrayClose(); //close disc tray
// extended funcs
void CALLBACK CDVDconfigure();
void CALLBACK CDVDabout();
s32 CALLBACK CDVDtest();
void CALLBACK CDVDnewDiskCB(void (*callback)());
#endif
/* DEV9 plugin API */
// if this file is included with this define
// the next api will not be skipped by the compiler
#ifdef DEV9defs
// basic funcs
// NOTE: The read/write functions CANNOT use XMM/MMX regs
// If you want to use them, need to save and restore current ones
s32 CALLBACK DEV9init();
s32 CALLBACK DEV9open(void *pDsp);
void CALLBACK DEV9close();
void CALLBACK DEV9shutdown();
u8 CALLBACK DEV9read8(u32 addr);
u16 CALLBACK DEV9read16(u32 addr);
u32 CALLBACK DEV9read32(u32 addr);
void CALLBACK DEV9write8(u32 addr, u8 value);
void CALLBACK DEV9write16(u32 addr, u16 value);
void CALLBACK DEV9write32(u32 addr, u32 value);
void CALLBACK DEV9readDMA8Mem(u32 *pMem, int size);
void CALLBACK DEV9writeDMA8Mem(u32 *pMem, int size);
// cycles = IOP cycles before calling callback,
// if callback returns 1 the irq is triggered, else not
void CALLBACK DEV9irqCallback(DEV9callback callback);
DEV9handler CALLBACK DEV9irqHandler(void);
// extended funcs
s32 CALLBACK DEV9freeze(int mode, freezeData *data);
void CALLBACK DEV9configure();
void CALLBACK DEV9about();
s32 CALLBACK DEV9test();
#endif
/* USB plugin API */
// if this file is included with this define
// the next api will not be skipped by the compiler
#ifdef USBdefs
// basic funcs
s32 CALLBACK USBinit();
s32 CALLBACK USBopen(void *pDsp);
void CALLBACK USBclose();
void CALLBACK USBshutdown();
u8 CALLBACK USBread8(u32 addr);
u16 CALLBACK USBread16(u32 addr);
u32 CALLBACK USBread32(u32 addr);
void CALLBACK USBwrite8(u32 addr, u8 value);
void CALLBACK USBwrite16(u32 addr, u16 value);
void CALLBACK USBwrite32(u32 addr, u32 value);
void CALLBACK USBasync(u32 cycles);
// cycles = IOP cycles before calling callback,
// if callback returns 1 the irq is triggered, else not
void CALLBACK USBirqCallback(USBcallback callback);
USBhandler CALLBACK USBirqHandler(void);
void CALLBACK USBsetRAM(void *mem);
// extended funcs
s32 CALLBACK USBfreeze(int mode, freezeData *data);
void CALLBACK USBconfigure();
void CALLBACK USBabout();
s32 CALLBACK USBtest();
#endif
/* FW plugin API */
// if this file is included with this define
// the next api will not be skipped by the compiler
#ifdef FWdefs
// basic funcs
// NOTE: The read/write functions CANNOT use XMM/MMX regs
// If you want to use them, need to save and restore current ones
s32 CALLBACK FWinit();
s32 CALLBACK FWopen(void *pDsp);
void CALLBACK FWclose();
void CALLBACK FWshutdown();
u32 CALLBACK FWread32(u32 addr);
void CALLBACK FWwrite32(u32 addr, u32 value);
void CALLBACK FWirqCallback(void (*callback)());
// extended funcs
s32 CALLBACK FWfreeze(int mode, freezeData *data);
void CALLBACK FWconfigure();
void CALLBACK FWabout();
s32 CALLBACK FWtest();
#endif
// might be useful for emulators
#ifdef PLUGINtypedefs
typedef u32 (CALLBACK* _PS2EgetLibType)(void);
typedef u32 (CALLBACK* _PS2EgetLibVersion2)(u32 type);
typedef char*(CALLBACK* _PS2EgetLibName)(void);
// GS
// NOTE: GSreadFIFOX/GSwriteCSR functions CANNOT use XMM/MMX regs
// If you want to use them, need to save and restore current ones
typedef s32 (CALLBACK* _GSinit)();
typedef s32 (CALLBACK* _GSopen)(void *pDsp, char *Title, int multithread);
typedef void (CALLBACK* _GSclose)();
typedef void (CALLBACK* _GSshutdown)();
typedef void (CALLBACK* _GSvsync)(int field);
typedef void (CALLBACK* _GSgifTransfer1)(u32 *pMem, u32 addr);
typedef void (CALLBACK* _GSgifTransfer2)(u32 *pMem, u32 size);
typedef void (CALLBACK* _GSgifTransfer3)(u32 *pMem, u32 size);
typedef void (CALLBACK* _GSgetLastTag)(u64* ptag); // returns the last tag processed (64 bits)
typedef void (CALLBACK* _GSgifSoftReset)(u32 mask);
typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem);
typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc);
typedef void (CALLBACK* _GSkeyEvent)(keyEvent* ev);
typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename);
typedef void (CALLBACK* _GSirqCallback)(void (*callback)());
typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...);
typedef void (CALLBACK* _GSsetBaseMem)(void*);
typedef void (CALLBACK* _GSsetGameCRC)(int, int);
typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip);
typedef int (CALLBACK* _GSsetupRecording)(int, void*);
typedef void (CALLBACK* _GSreset)();
typedef void (CALLBACK* _GSwriteCSR)(u32 value);
typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info);
#ifdef _WIN32
typedef s32 (CALLBACK* _GSsetWindowInfo)(winInfo *info);
#endif
typedef void (CALLBACK* _GSmakeSnapshot)(char *path);
typedef void (CALLBACK* _GSmakeSnapshot2)(char *path, int*, int);
typedef s32 (CALLBACK* _GSfreeze)(int mode, freezeData *data);
typedef void (CALLBACK* _GSconfigure)();
typedef s32 (CALLBACK* _GStest)();
typedef void (CALLBACK* _GSabout)();
// PAD
typedef s32 (CALLBACK* _PADinit)(u32 flags);
typedef s32 (CALLBACK* _PADopen)(void *pDsp);
typedef void (CALLBACK* _PADclose)();
typedef void (CALLBACK* _PADshutdown)();
typedef keyEvent* (CALLBACK* _PADkeyEvent)();
typedef u8 (CALLBACK* _PADstartPoll)(int pad);
typedef u8 (CALLBACK* _PADpoll)(u8 value);
typedef u32 (CALLBACK* _PADquery)();
typedef void (CALLBACK* _PADupdate)(int pad);
typedef void (CALLBACK* _PADgsDriverInfo)(GSdriverInfo *info);
typedef void (CALLBACK* _PADconfigure)();
typedef s32 (CALLBACK* _PADtest)();
typedef void (CALLBACK* _PADabout)();
// SIO
typedef s32 (CALLBACK* _SIOinit)(u32 port, u32 slot, SIOchangeSlotCB f);
typedef s32 (CALLBACK* _SIOopen)(void *pDsp);
typedef void (CALLBACK* _SIOclose)();
typedef void (CALLBACK* _SIOshutdown)();
typedef u8 (CALLBACK* _SIOstartPoll)(u8 value);
typedef u8 (CALLBACK* _SIOpoll)(u8 value);
typedef u32 (CALLBACK* _SIOquery)();
typedef void (CALLBACK* _SIOconfigure)();
typedef s32 (CALLBACK* _SIOtest)();
typedef void (CALLBACK* _SIOabout)();
// SPU2
// NOTE: The read/write functions CANNOT use XMM/MMX regs
// If you want to use them, need to save and restore current ones
typedef s32 (CALLBACK* _SPU2init)();
typedef s32 (CALLBACK* _SPU2open)(void *pDsp);
typedef void (CALLBACK* _SPU2close)();
typedef void (CALLBACK* _SPU2shutdown)();
typedef void (CALLBACK* _SPU2write)(u32 mem, u16 value);
typedef u16 (CALLBACK* _SPU2read)(u32 mem);
typedef void (CALLBACK* _SPU2readDMA4Mem)(u16 *pMem, int size);
typedef void (CALLBACK* _SPU2writeDMA4Mem)(u16 *pMem, int size);
typedef void (CALLBACK* _SPU2interruptDMA4)();
typedef void (CALLBACK* _SPU2readDMA7Mem)(u16 *pMem, int size);
typedef void (CALLBACK* _SPU2writeDMA7Mem)(u16 *pMem, int size);
typedef void (CALLBACK* _SPU2setDMABaseAddr)(uptr baseaddr);
typedef void (CALLBACK* _SPU2interruptDMA7)();
typedef void (CALLBACK* _SPU2irqCallback)(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)());
typedef int (CALLBACK* _SPU2setupRecording)(int, void*);
typedef void (CALLBACK* _SPU2setClockPtr)(u32*ptr);
typedef u32 (CALLBACK* _SPU2ReadMemAddr)(int core);
typedef void (CALLBACK* _SPU2WriteMemAddr)(int core,u32 value);
typedef void (CALLBACK* _SPU2async)(u32 cycles);
typedef s32 (CALLBACK* _SPU2freeze)(int mode, freezeData *data);
typedef void (CALLBACK* _SPU2configure)();
typedef s32 (CALLBACK* _SPU2test)();
typedef void (CALLBACK* _SPU2about)();
// CDVD
// NOTE: The read/write functions CANNOT use XMM/MMX regs
// If you want to use them, need to save and restore current ones
typedef s32 (CALLBACK* _CDVDinit)();
typedef s32 (CALLBACK* _CDVDopen)(const char* pTitleFilename);
typedef void (CALLBACK* _CDVDclose)();
typedef void (CALLBACK* _CDVDshutdown)();
typedef s32 (CALLBACK* _CDVDreadTrack)(u32 lsn, int mode);
typedef u8* (CALLBACK* _CDVDgetBuffer)();
typedef s32 (CALLBACK* _CDVDreadSubQ)(u32 lsn, cdvdSubQ* subq);
typedef s32 (CALLBACK* _CDVDgetTN)(cdvdTN *Buffer);
typedef s32 (CALLBACK* _CDVDgetTD)(u8 Track, cdvdTD *Buffer);
typedef s32 (CALLBACK* _CDVDgetTOC)(void* toc);
typedef s32 (CALLBACK* _CDVDgetDiskType)();
typedef s32 (CALLBACK* _CDVDgetTrayStatus)();
typedef s32 (CALLBACK* _CDVDctrlTrayOpen)();
typedef s32 (CALLBACK* _CDVDctrlTrayClose)();
typedef void (CALLBACK* _CDVDconfigure)();
typedef s32 (CALLBACK* _CDVDtest)();
typedef void (CALLBACK* _CDVDabout)();
typedef void (CALLBACK* _CDVDnewDiskCB)(void (*callback)());
// DEV9
// NOTE: The read/write functions CANNOT use XMM/MMX regs
// If you want to use them, need to save and restore current ones
typedef s32 (CALLBACK* _DEV9init)();
typedef s32 (CALLBACK* _DEV9open)(void *pDsp);
typedef void (CALLBACK* _DEV9close)();
typedef void (CALLBACK* _DEV9shutdown)();
typedef u8 (CALLBACK* _DEV9read8)(u32 mem);
typedef u16 (CALLBACK* _DEV9read16)(u32 mem);
typedef u32 (CALLBACK* _DEV9read32)(u32 mem);
typedef void (CALLBACK* _DEV9write8)(u32 mem, u8 value);
typedef void (CALLBACK* _DEV9write16)(u32 mem, u16 value);
typedef void (CALLBACK* _DEV9write32)(u32 mem, u32 value);
typedef void (CALLBACK* _DEV9readDMA8Mem)(u32 *pMem, int size);
typedef void (CALLBACK* _DEV9writeDMA8Mem)(u32 *pMem, int size);
typedef void (CALLBACK* _DEV9irqCallback)(DEV9callback callback);
typedef DEV9handler (CALLBACK* _DEV9irqHandler)(void);
typedef s32 (CALLBACK* _DEV9freeze)(int mode, freezeData *data);
typedef void (CALLBACK* _DEV9configure)();
typedef s32 (CALLBACK* _DEV9test)();
typedef void (CALLBACK* _DEV9about)();
// USB
// NOTE: The read/write functions CANNOT use XMM/MMX regs
// If you want to use them, need to save and restore current ones
typedef s32 (CALLBACK* _USBinit)();
typedef s32 (CALLBACK* _USBopen)(void *pDsp);
typedef void (CALLBACK* _USBclose)();
typedef void (CALLBACK* _USBshutdown)();
typedef u8 (CALLBACK* _USBread8)(u32 mem);
typedef u16 (CALLBACK* _USBread16)(u32 mem);
typedef u32 (CALLBACK* _USBread32)(u32 mem);
typedef void (CALLBACK* _USBwrite8)(u32 mem, u8 value);
typedef void (CALLBACK* _USBwrite16)(u32 mem, u16 value);
typedef void (CALLBACK* _USBwrite32)(u32 mem, u32 value);
typedef void (CALLBACK* _USBasync)(u32 cycles);
typedef void (CALLBACK* _USBirqCallback)(USBcallback callback);
typedef USBhandler (CALLBACK* _USBirqHandler)(void);
typedef void (CALLBACK* _USBsetRAM)(void *mem);
typedef s32 (CALLBACK* _USBfreeze)(int mode, freezeData *data);
typedef void (CALLBACK* _USBconfigure)();
typedef s32 (CALLBACK* _USBtest)();
typedef void (CALLBACK* _USBabout)();
//FW
typedef s32 (CALLBACK* _FWinit)();
typedef s32 (CALLBACK* _FWopen)(void *pDsp);
typedef void (CALLBACK* _FWclose)();
typedef void (CALLBACK* _FWshutdown)();
typedef u32 (CALLBACK* _FWread32)(u32 mem);
typedef void (CALLBACK* _FWwrite32)(u32 mem, u32 value);
typedef void (CALLBACK* _FWirqCallback)(void (*callback)());
typedef s32 (CALLBACK* _FWfreeze)(int mode, freezeData *data);
typedef void (CALLBACK* _FWconfigure)();
typedef s32 (CALLBACK* _FWtest)();
typedef void (CALLBACK* _FWabout)();
#endif
#ifdef PLUGINfuncs
// GS
_GSinit GSinit;
_GSopen GSopen;
_GSclose GSclose;
_GSshutdown GSshutdown;
_GSvsync GSvsync;
_GSgifTransfer1 GSgifTransfer1;
_GSgifTransfer2 GSgifTransfer2;
_GSgifTransfer3 GSgifTransfer3;
_GSgetLastTag GSgetLastTag;
_GSgifSoftReset GSgifSoftReset;
_GSreadFIFO GSreadFIFO;
_GSreadFIFO2 GSreadFIFO2;
_GSkeyEvent GSkeyEvent;
_GSchangeSaveState GSchangeSaveState;
_GSmakeSnapshot GSmakeSnapshot;
_GSmakeSnapshot2 GSmakeSnapshot2;
_GSirqCallback GSirqCallback;
_GSprintf GSprintf;
_GSsetBaseMem GSsetBaseMem;
_GSsetGameCRC GSsetGameCRC;
_GSsetFrameSkip GSsetFrameSkip;
_GSsetupRecording GSsetupRecording;
_GSreset GSreset;
_GSwriteCSR GSwriteCSR;
_GSgetDriverInfo GSgetDriverInfo;
#ifdef _WIN32
_GSsetWindowInfo GSsetWindowInfo;
#endif
_GSfreeze GSfreeze;
_GSconfigure GSconfigure;
_GStest GStest;
_GSabout GSabout;
// PAD1
_PADinit PAD1init;
_PADopen PAD1open;
_PADclose PAD1close;
_PADshutdown PAD1shutdown;
_PADkeyEvent PAD1keyEvent;
_PADstartPoll PAD1startPoll;
_PADpoll PAD1poll;
_PADquery PAD1query;
_PADupdate PAD1update;
_PADgsDriverInfo PAD1gsDriverInfo;
_PADconfigure PAD1configure;
_PADtest PAD1test;
_PADabout PAD1about;
// PAD2
_PADinit PAD2init;
_PADopen PAD2open;
_PADclose PAD2close;
_PADshutdown PAD2shutdown;
_PADkeyEvent PAD2keyEvent;
_PADstartPoll PAD2startPoll;
_PADpoll PAD2poll;
_PADquery PAD2query;
_PADupdate PAD2update;
_PADgsDriverInfo PAD2gsDriverInfo;
_PADconfigure PAD2configure;
_PADtest PAD2test;
_PADabout PAD2about;
// SIO[2]
_SIOinit SIOinit[2][9];
_SIOopen SIOopen[2][9];
_SIOclose SIOclose[2][9];
_SIOshutdown SIOshutdown[2][9];
_SIOstartPoll SIOstartPoll[2][9];
_SIOpoll SIOpoll[2][9];
_SIOquery SIOquery[2][9];
_SIOconfigure SIOconfigure[2][9];
_SIOtest SIOtest[2][9];
_SIOabout SIOabout[2][9];
// SPU2
_SPU2init SPU2init;
_SPU2open SPU2open;
_SPU2close SPU2close;
_SPU2shutdown SPU2shutdown;
_SPU2write SPU2write;
_SPU2read SPU2read;
_SPU2readDMA4Mem SPU2readDMA4Mem;
_SPU2writeDMA4Mem SPU2writeDMA4Mem;
_SPU2interruptDMA4 SPU2interruptDMA4;
_SPU2readDMA7Mem SPU2readDMA7Mem;
_SPU2writeDMA7Mem SPU2writeDMA7Mem;
_SPU2setDMABaseAddr SPU2setDMABaseAddr;
_SPU2interruptDMA7 SPU2interruptDMA7;
_SPU2ReadMemAddr SPU2ReadMemAddr;
_SPU2setupRecording SPU2setupRecording;
_SPU2WriteMemAddr SPU2WriteMemAddr;
_SPU2irqCallback SPU2irqCallback;
_SPU2setClockPtr SPU2setClockPtr;
_SPU2async SPU2async;
_SPU2freeze SPU2freeze;
_SPU2configure SPU2configure;
_SPU2test SPU2test;
_SPU2about SPU2about;
// CDVD
_CDVDinit CDVDinit;
_CDVDopen CDVDopen;
_CDVDclose CDVDclose;
_CDVDshutdown CDVDshutdown;
_CDVDreadTrack CDVDreadTrack;
_CDVDgetBuffer CDVDgetBuffer;
_CDVDreadSubQ CDVDreadSubQ;
_CDVDgetTN CDVDgetTN;
_CDVDgetTD CDVDgetTD;
_CDVDgetTOC CDVDgetTOC;
_CDVDgetDiskType CDVDgetDiskType;
_CDVDgetTrayStatus CDVDgetTrayStatus;
_CDVDctrlTrayOpen CDVDctrlTrayOpen;
_CDVDctrlTrayClose CDVDctrlTrayClose;
_CDVDconfigure CDVDconfigure;
_CDVDtest CDVDtest;
_CDVDabout CDVDabout;
_CDVDnewDiskCB CDVDnewDiskCB;
// DEV9
_DEV9init DEV9init;
_DEV9open DEV9open;
_DEV9close DEV9close;
_DEV9shutdown DEV9shutdown;
_DEV9read8 DEV9read8;
_DEV9read16 DEV9read16;
_DEV9read32 DEV9read32;
_DEV9write8 DEV9write8;
_DEV9write16 DEV9write16;
_DEV9write32 DEV9write32;
_DEV9readDMA8Mem DEV9readDMA8Mem;
_DEV9writeDMA8Mem DEV9writeDMA8Mem;
_DEV9irqCallback DEV9irqCallback;
_DEV9irqHandler DEV9irqHandler;
_DEV9configure DEV9configure;
_DEV9freeze DEV9freeze;
_DEV9test DEV9test;
_DEV9about DEV9about;
// USB
_USBinit USBinit;
_USBopen USBopen;
_USBclose USBclose;
_USBshutdown USBshutdown;
_USBread8 USBread8;
_USBread16 USBread16;
_USBread32 USBread32;
_USBwrite8 USBwrite8;
_USBwrite16 USBwrite16;
_USBwrite32 USBwrite32;
_USBasync USBasync;
_USBirqCallback USBirqCallback;
_USBirqHandler USBirqHandler;
_USBsetRAM USBsetRAM;
_USBconfigure USBconfigure;
_USBfreeze USBfreeze;
_USBtest USBtest;
_USBabout USBabout;
// FW
_FWinit FWinit;
_FWopen FWopen;
_FWclose FWclose;
_FWshutdown FWshutdown;
_FWread32 FWread32;
_FWwrite32 FWwrite32;
_FWirqCallback FWirqCallback;
_FWconfigure FWconfigure;
_FWfreeze FWfreeze;
_FWtest FWtest;
_FWabout FWabout;
#endif
#endif /* __PS2EDEFS_H__ */

View File

@ -0,0 +1,88 @@
#ifndef __PS2ETYPES_H__
#define __PS2ETYPES_H__
#if defined (__linux__) && !defined(__LINUX__) // some distributions are lower case
#define __LINUX__
#endif
#ifdef __CYGWIN__
#define _WIN32
#endif
#ifdef _WIN32
#include <windows.h>
#endif
#ifndef ARRAYSIZE
#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0]))
#endif
// Basic types
#if defined(_MSC_VER)
typedef __int8 s8;
typedef __int16 s16;
typedef __int32 s32;
typedef __int64 s64;
typedef unsigned __int8 u8;
typedef unsigned __int16 u16;
typedef unsigned __int32 u32;
typedef unsigned __int64 u64;
#define PCSX2_ALIGNED16(x) __declspec(align(16)) x
#define PCSX2_ALIGNED16_DECL(x) __declspec(align(16)) x
#else
typedef char s8;
typedef short s16;
typedef int s32;
typedef long long s64;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
#ifdef __LINUX__
typedef union _LARGE_INTEGER
{
long long QuadPart;
} LARGE_INTEGER;
#endif
#if defined(__MINGW32__)
#define PCSX2_ALIGNED16(x) __declspec(align(16)) x
#else
#define PCSX2_ALIGNED16(x) x __attribute((aligned(16)))
#endif
#define PCSX2_ALIGNED16_DECL(x) x
#ifndef __forceinline
#define __forceinline inline
#endif
#endif // _MSC_VER
#if defined(__x86_64__)
typedef u64 uptr;
typedef s64 sptr;
#else
typedef u32 uptr;
typedef s32 sptr;
#endif
typedef struct {
int size;
s8 *data;
} freezeData;
/* common defines */
#ifndef C_ASSERT
#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
#endif
#endif /* __PS2ETYPES_H__ */

BIN
plugins/spu2ghz/SPU2ghz.aps Normal file

Binary file not shown.

View File

@ -0,0 +1,57 @@
;GiGaHeRz's SPU2 Driver
;Copyright (c) David Quintana (gigaherz@gmail.com)
;
;This library is free software; you can redistribute it and/or
;modify it under the terms of the GNU Lesser General Public
;License as published by the Free Software Foundation; either
;version 2.1 of the License, or (at your option) any later version.
;
;This library is distributed in the hope that it will be useful,
;but WITHOUT ANY WARRANTY; without even the implied warranty of
;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;Lesser General Public License for more details.
;
;You should have received a copy of the GNU Lesser General Public
;License along with this library; if not, write to the Free Software
;Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
;
; SPU2ghz.def : Declares the module parameters for the DLL.
LIBRARY "SPU2ghz"
EXPORTS
; Explicit exports can go here
PS2EgetLibType @2
PS2EgetLibName @3
PS2EgetLibVersion2 @4
SPU2init @5
SPU2shutdown @6
SPU2open @7
SPU2close @8
SPU2write @9
SPU2read @10
SPU2readDMA4Mem @11
SPU2writeDMA4Mem @12
SPU2readDMA7Mem @13
SPU2writeDMA7Mem @14
SPU2async @15
SPU2interruptDMA4 @16
SPU2interruptDMA7 @17
SPU2irqCallback @18
SPU2setupRecording @19
SPU2configure @20
SPU2test @21
SPU2about @22
SPU2ReadMemAddr @23
SPU2WriteMemAddr @24
SPU2setClockPtr @25
SPU2setDMABaseAddr @26
SPU2replay = s2r_replay @27
SPU2freeze @28

274
plugins/spu2ghz/SPU2ghz.dsp Normal file
View File

@ -0,0 +1,274 @@
# Microsoft Developer Studio Project File - Name="SPU2ghz" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=SPU2ghz - Win32 Debug Banyoles
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "SPU2ghz.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "SPU2ghz.mak" CFG="SPU2ghz - Win32 Debug Banyoles"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "SPU2ghz - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "SPU2ghz - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "SPU2ghz - Win32 Debug Threaded" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "SPU2ghz - Win32 Debug2" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "SPU2ghz - Win32 Debug Banyoles" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "SPU2ghz - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SPU2GHZ_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "__WIN32__" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SPU2GHZ_EXPORTS" /FR /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0xc0a /d "NDEBUG"
# ADD RSC /l 0xc0a /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /dll /machine:I386 /out:"../../SPU2ghz.dll"
!ELSEIF "$(CFG)" == "SPU2ghz - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SPU2GHZ_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "__WIN32__" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SPU2GHZ_EXPORTS" /FR /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0xc0a /d "_DEBUG"
# ADD RSC /l 0xc0a /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib fmodvc.lib /nologo /dll /debug /machine:I386 /out:"c:\Coses\Emulation\PS2\pcsx2\plugins\SPU2ghz1.dll" /pdbtype:sept
!ELSEIF "$(CFG)" == "SPU2ghz - Win32 Debug Threaded"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "SPU2ghz___Win32_Debug_Threaded"
# PROP BASE Intermediate_Dir "SPU2ghz___Win32_Debug_Threaded"
# PROP BASE Ignore_Export_Lib 0
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "SPU2ghz___Win32_Debug_Threaded"
# PROP Intermediate_Dir "SPU2ghz___Win32_Debug_Threaded"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "__WIN32__" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SPU2GHZ_EXPORTS" /FR /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "__WIN32__" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SPU2GHZ_EXPORTS" /D "USETHREAD" /FR /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0xc0a /d "_DEBUG"
# ADD RSC /l 0xc0a /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /dll /debug /machine:I386 /out:"c:\Coses\Emulation\PS2\pcsx2\plugins\SPU2ghz1.dll" /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /dll /debug /machine:I386 /out:"c:\Coses\Emulation\PS2\pcsx2\plugins\SPU2ghz1_thread.dll" /pdbtype:sept
!ELSEIF "$(CFG)" == "SPU2ghz - Win32 Debug2"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "SPU2ghz___Win32_Debug2"
# PROP BASE Intermediate_Dir "SPU2ghz___Win32_Debug2"
# PROP BASE Ignore_Export_Lib 0
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "SPU2ghz___Win32_Debug2"
# PROP Intermediate_Dir "SPU2ghz___Win32_Debug2"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "__WIN32__" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SPU2GHZ_EXPORTS" /FR /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "__WIN32__" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SPU2GHZ_EXPORTS" /D "OLDSPECS" /FR /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0xc0a /d "_DEBUG"
# ADD RSC /l 0xc0a /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /dll /debug /machine:I386 /out:"c:\Coses\Emulation\PS2\pcsx2\plugins\SPU2ghz1.dll" /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /dll /debug /machine:I386 /out:"c:\Coses\Emulation\PS2\pcsx2\plugins\SPU2ghz1_old.dll" /pdbtype:sept
!ELSEIF "$(CFG)" == "SPU2ghz - Win32 Debug Banyoles"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "SPU2ghz___Win32_Debug_Banyoles"
# PROP BASE Intermediate_Dir "SPU2ghz___Win32_Debug_Banyoles"
# PROP BASE Ignore_Export_Lib 0
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "SPU2ghz___Win32_Debug_Banyoles"
# PROP Intermediate_Dir "SPU2ghz___Win32_Debug_Banyoles"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "__WIN32__" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SPU2GHZ_EXPORTS" /FR /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "__WIN32__" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SPU2GHZ_EXPORTS" /FR /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0xc0a /d "_DEBUG"
# ADD RSC /l 0xc0a /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib fmodvc.lib /nologo /dll /debug /machine:I386 /out:"c:\Coses\Emulation\PS2\pcsx2\plugins\SPU2ghz1.dll" /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winmm.lib fmodvc.lib /nologo /dll /debug /machine:I386 /out:".\SPU2ghz1.dll" /pdbtype:sept
!ENDIF
# Begin Target
# Name "SPU2ghz - Win32 Release"
# Name "SPU2ghz - Win32 Debug"
# Name "SPU2ghz - Win32 Debug Threaded"
# Name "SPU2ghz - Win32 Debug2"
# Name "SPU2ghz - Win32 Debug Banyoles"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\config.c
# End Source File
# Begin Source File
SOURCE=.\debug.c
# End Source File
# Begin Source File
SOURCE=.\dma.c
# End Source File
# Begin Source File
SOURCE=.\fmodout.c
# End Source File
# Begin Source File
SOURCE=.\mixer.c
# End Source File
# Begin Source File
SOURCE=.\sndout.c
# End Source File
# Begin Source File
SOURCE=.\spu2.c
# End Source File
# Begin Source File
SOURCE=.\SPU2ghz.def
# End Source File
# Begin Source File
SOURCE=.\waveout.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\config.h
# End Source File
# Begin Source File
SOURCE=.\debug.h
# End Source File
# Begin Source File
SOURCE=.\defs.h
# End Source File
# Begin Source File
SOURCE=.\dma.h
# End Source File
# Begin Source File
SOURCE=.\mixer.h
# End Source File
# Begin Source File
SOURCE=.\PS2Edefs.h
# End Source File
# Begin Source File
SOURCE=.\PS2Etypes.h
# End Source File
# Begin Source File
SOURCE=.\regs.h
# End Source File
# Begin Source File
SOURCE=.\sndout.h
# End Source File
# Begin Source File
SOURCE=.\spu2.h
# End Source File
# End Group
# Begin Group "Documents"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\LGPL.txt
# End Source File
# Begin Source File
SOURCE=.\License.txt
# End Source File
# End Group
# End Target
# End Project

View File

@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "SPU2ghz"=".\SPU2ghz.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

253
plugins/spu2ghz/SPU2ghz.rc Normal file
View File

@ -0,0 +1,253 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Spanish resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESN)
#ifdef _WIN32
LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_MODERN
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_CONFIG DIALOGEX 3, 1, 414, 217
STYLE DS_SETFONT | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "SPU2ghz Settings"
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
PUSHBUTTON "OK",IDOK,300,198,54,15,NOT WS_TABSTOP
PUSHBUTTON "Cancel",IDCANCEL,354,198,54,15,NOT WS_TABSTOP
GROUPBOX "Effects (Reverb) Settings",IDC_STATIC,6,156,119,30
CHECKBOX "Enable Effect Processing",IDC_EFFECTS,12,168,95,10,NOT WS_TABSTOP
GROUPBOX "Output Settings",IDC_STATIC,132,6,119,111
LTEXT "Buffer Size",IDC_STATIC,138,35,35,8,NOT WS_GROUP
LTEXT "Sample Rate",IDC_STATIC,139,19,42,8,NOT WS_GROUP
GROUPBOX "Mixing Settings",IDC_STATIC,6,6,119,80
LTEXT "Interpolation:",IDC_STATIC,11,58,42,8,NOT WS_GROUP
GROUPBOX "",IDC_STATIC,264,18,135,61
GROUPBOX "Dumps (on close)",IDC_STATIC,264,131,135,51
CHECKBOX "Dump Register Data",IDC_DUMPREGS,270,169,80,10,NOT WS_TABSTOP
CHECKBOX "Dump Memory Contents",IDC_DUMPMEM,270,156,91,10,NOT WS_TABSTOP
CHECKBOX "Dump Core and Voice State",IDC_DUMPCORE,270,145,104,10,NOT WS_TABSTOP
GROUPBOX "Logging",IDC_STATIC,263,80,136,50
CHECKBOX "Log Audio Output",IDC_LOGWAVE,269,116,71,10,NOT WS_TABSTOP
CHECKBOX "Log DMA Writes",IDC_LOGDMA,269,104,68,10,NOT WS_TABSTOP
CHECKBOX "Log Register/DMA Actions",IDC_LOGREGS,269,92,101,10,NOT WS_TABSTOP
CHECKBOX "KeyOn/Off Events",IDC_MSGKEY,276,30,74,10,NOT WS_TABSTOP
COMBOBOX IDC_INTERPOLATE,12,66,108,84,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_SRATE,192,18,54,201,CBS_DROPDOWN | WS_DISABLED | WS_TABSTOP,WS_EX_RIGHT
CONTROL "Slider2",IDC_BUFFER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,138,42,65,10
EDITTEXT IDC_BSIZE,204,42,42,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
LTEXT "Output Module:",IDC_STATIC,12,16,50,8,NOT WS_GROUP
COMBOBOX IDC_OUTPUT,12,24,108,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Number of Buffers:",IDC_STATIC,139,62,60,8
EDITTEXT IDC_BCOUNT,204,60,42,12,ES_RIGHT | ES_AUTOHSCROLL
GROUPBOX "",IDC_STATIC,258,6,150,180
CHECKBOX "Enable Debug Options",IDC_DEBUG,264,6,87,10,NOT WS_TABSTOP
CONTROL "DMA Operations",IDC_MSGDMA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,54,68,10
CONTROL "AutoDMA Operations",IDC_MSGADMA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,282,66,83,10
CONTROL "Voice Stop Events",IDC_MSGVOICE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,276,42,75,10
CONTROL "Show In Console",IDC_MSGSHOW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,270,18,69,10
GROUPBOX "Speed Limiter",IDC_STATIC,132,119,120,68
LTEXT "The number value works better if it's in the 5-20 range. The buffer size works better in powers of 2 (1024/2048) specially in Vista.",IDC_STATIC,138,75,108,35
CONTROL "Limit speed to output speed.",IDC_SPEEDLIMIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,138,132,108,12
PUSHBUTTON "Configure...",IDC_OUTCONF,72,42,48,12
LTEXT "WARNING: The effects processing is experimental and _could_ hurt your ears .\n If that happens, tell me about what game, so I can fix it!",IDC_STATIC,20,191,255,21
GROUPBOX "DSP && Stretching",IDC_STATIC,6,87,119,68
CONTROL "Enable Winamp DSP plugin",IDC_DSP_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,100,103,10
LTEXT "(configure in the .ini)",IDC_STATIC,41,116,64,8
CONTROL "Enable Timestretcher",IDC_TS_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,137,83,10
LTEXT "Use this to time the FPS to SPU2. Makes the audio play at best speed when your games allow it.",IDC_STATIC,138,149,108,31
END
IDD_DEBUG DIALOGEX 0, 0, 326, 525
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "SPU2ghz Debug"
FONT 9, "Lucida Console", 400, 0, 0x0
BEGIN
DEFPUSHBUTTON "Close",IDOK,269,504,50,14
END
IDD_DSOUND DIALOGEX 0, 0, 186, 58
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "DirectSound Output Module Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,75,37,50,14
PUSHBUTTON "Cancel",IDCANCEL,129,37,50,14
COMBOBOX IDC_DS_DEVICE,7,17,172,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "DirectSound Device",IDC_STATIC,7,7,63,8
END
IDD_DSOUND51 DIALOGEX 0, 0, 265, 182
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "DirectSound 5.1 Output Module Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,154,161,50,14
PUSHBUTTON "Cancel",IDCANCEL,208,161,50,14
COMBOBOX IDC_DS_DEVICE,7,17,251,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "DirectSound Device",IDC_STATIC,7,7,63,8
CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,18,54,30,36
CONTROL "",IDC_SLIDER2,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,60,56,30,34
CONTROL "",IDC_SLIDER3,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,102,56,30,34
GROUPBOX "Surround Volume Correction",IDC_STATIC,7,36,142,139
CTEXT "Center",IDC_STATIC,54,48,42,8
CTEXT "Left",IDC_STATIC,12,48,42,8
CTEXT "Right",IDC_STATIC,96,48,42,8
CONTROL "",IDC_SLIDER4,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,18,116,30,40
CONTROL "",IDC_SLIDER5,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,60,116,30,40
CONTROL "",IDC_SLIDER6,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,102,116,30,40
CTEXT "LFE (sub)",IDC_STATIC,54,108,42,8
CTEXT "Rear Left",IDC_STATIC,12,108,42,8
CTEXT "Rear Right",IDC_STATIC,96,108,42,8
GROUPBOX "Other Tweaks",IDC_STATIC,155,36,103,120
CONTROL "",IDC_SLIDER7,"msctls_trackbar32",TBS_VERT | TBS_BOTH | WS_TABSTOP,168,56,30,49
CTEXT "Center in LR",IDC_STATIC,162,48,42,8
EDITTEXT IDC_EDIT1,18,90,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT2,60,90,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT3,102,90,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT4,18,156,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT5,60,156,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT6,102,156,30,14,ES_AUTOHSCROLL
EDITTEXT IDC_EDIT7,168,108,30,14,ES_AUTOHSCROLL
END
IDD_ASIO DIALOGEX 0, 0, 186, 58
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "ASIO Output Module Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,75,37,50,14
PUSHBUTTON "Cancel",IDCANCEL,129,37,50,14
COMBOBOX IDC_DS_DEVICE,7,17,172,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "ASIO Driver",IDC_STATIC,7,7,39,8
END
IDD_WAVEOUT DIALOGEX 0, 0, 186, 58
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "waveOut Output Module Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,75,37,50,14
PUSHBUTTON "Cancel",IDCANCEL,129,37,50,14
COMBOBOX IDC_DS_DEVICE,7,17,172,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "waveOut Device",IDC_STATIC,7,7,54,8
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_CONFIG, DIALOG
BEGIN
LEFTMARGIN, 6
RIGHTMARGIN, 408
TOPMARGIN, 5
BOTTOMMARGIN, 212
END
IDD_DEBUG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 319
TOPMARGIN, 7
BOTTOMMARGIN, 518
END
IDD_DSOUND, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 51
END
IDD_DSOUND51, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 258
TOPMARGIN, 7
BOTTOMMARGIN, 175
END
IDD_ASIO, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 51
END
IDD_WAVEOUT, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 51
END
END
#endif // APSTUDIO_INVOKED
#endif // Spanish resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -0,0 +1,23 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPU2ghz", "SPU2ghz.vcproj", "{D7CB1F9C-E056-459C-B4EF-A6E7ABE2FCAB}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectDependencies) = postSolution
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{D7CB1F9C-E056-459C-B4EF-A6E7ABE2FCAB}.Debug.ActiveCfg = Debug|Win32
{D7CB1F9C-E056-459C-B4EF-A6E7ABE2FCAB}.Debug.Build.0 = Debug|Win32
{D7CB1F9C-E056-459C-B4EF-A6E7ABE2FCAB}.Release.ActiveCfg = Release|Win32
{D7CB1F9C-E056-459C-B4EF-A6E7ABE2FCAB}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,425 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="SPU2ghz"
RootNamespace="SPU2ghz"
SccProjectName=""
SccLocalPath="">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory=".\Debug"
IntermediateDirectory=".\Debug"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="_DEBUG;__WIN32__;WIN32;__MSCW32__;_WINDOWS;_USRDLL;SPU2GHZ_EXPORTS"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="2"
PrecompiledHeaderFile=".\Debug/SPU2ghz.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="TRUE"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="winmm.lib ./fmodapi/lib/fmodvc.lib"
OutputFile="F:\Coses\Emulation\PS2\pcsx2\plugins\SPU2ghz.dll"
LinkIncremental="2"
SuppressStartupBanner="TRUE"
ModuleDefinitionFile=".\SPU2ghz.def"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="./Debug/SPU2ghz1.pdb"
ImportLibrary=".\Debug/SPU2ghz1.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="TRUE"
SuppressStartupBanner="TRUE"
TargetEnvironment="1"
TypeLibraryName=".\Debug/SPU2ghz.tlb"
HeaderFileName=""/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="3082"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2"
WholeProgramOptimization="FALSE">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"
OptimizeForProcessor="2"
PreprocessorDefinitions="NDEBUG;__WIN32__;__MSCW32__;WIN32;_WINDOWS;_USRDLL;SPU2GHZ_EXPORTS"
StringPooling="TRUE"
RuntimeLibrary="0"
EnableFunctionLevelLinking="TRUE"
EnableEnhancedInstructionSet="1"
UsePrecompiledHeader="2"
PrecompiledHeaderFile=".\Release/SPU2ghz.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="TRUE"
Detect64BitPortabilityProblems="TRUE"
CompileAs="1"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="winmm.lib ./fmodapi/lib/fmodvc.lib"
OutputFile="F:\Coses\Emulation\PS2\pcsx2\plugins\SPU2ghz.dll"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
ModuleDefinitionFile=".\SPU2ghz.def"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="c:\Coses\Emulation\PS2\pcsx2\plugins\SPU2ghz.pdb"
GenerateMapFile="TRUE"
ImportLibrary=".\Release/SPU2ghz.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="TRUE"
SuppressStartupBanner="TRUE"
TargetEnvironment="1"
TypeLibraryName=".\Release/SPU2ghz.tlb"
HeaderFileName=""/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="3082"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
<File
RelativePath=".\asioout.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\config.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\debug.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\dma.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\fmodout.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\mixer.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\sndout.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\spu2.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath="SPU2ghz.def">
</File>
<File
RelativePath=".\SPU2ghz.rc">
</File>
<File
RelativePath=".\spu2replay.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\utf8.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\wavedump_wav.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\waveout.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<Filter
Name="ASIO"
Filter="">
<File
RelativePath=".\asio\asio.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\asio\ASIOConvertSamples.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\asio\asiodrivers.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\asio\asiolist.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\asio\combase.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
<File
RelativePath=".\asio\debugmessage.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
CompileAs="2"/>
</FileConfiguration>
</File>
</Filter>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl">
<File
RelativePath="config.h">
</File>
<File
RelativePath="debug.h">
</File>
<File
RelativePath="defs.h">
</File>
<File
RelativePath="dma.h">
</File>
<File
RelativePath="mixer.h">
</File>
<File
RelativePath="PS2Edefs.h">
</File>
<File
RelativePath="PS2Etypes.h">
</File>
<File
RelativePath="regs.h">
</File>
<File
RelativePath=".\resource.h">
</File>
<File
RelativePath="sndout.h">
</File>
<File
RelativePath=".\spdif.h">
</File>
<File
RelativePath="spu2.h">
</File>
<File
RelativePath=".\spu2replay.h">
</File>
<Filter
Name="ASIO"
Filter="">
<File
RelativePath=".\asio\asio.h">
</File>
<File
RelativePath=".\asio\ASIOConvertSamples.h">
</File>
<File
RelativePath=".\asio\asiodrivers.h">
</File>
<File
RelativePath=".\asio\asiolist.h">
</File>
<File
RelativePath=".\asio\asiosys.h">
</File>
<File
RelativePath=".\asio\combase.h">
</File>
<File
RelativePath=".\asio\ginclude.h">
</File>
<File
RelativePath=".\asio\iasiodrv.h">
</File>
<File
RelativePath=".\asio\wxdebug.h">
</File>
</Filter>
</Filter>
<Filter
Name="Documents"
Filter="">
<File
RelativePath="LGPL.txt">
</File>
<File
RelativePath="License.txt">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,946 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Intel C++ Project"
Version="10.1"
Name="SPU2ghz_vs2005"
ProjectGUID="{09981E32-E8D9-465E-A5D2-4077FE49459B}"
RootNamespace="SPU2ghz_vs2005"
VCNestedProjectGUID="{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}"
VCNestedProjectCRC32="2398778152"
VCNestedProjectFileName="SPU2ghz_intel.vcproj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Release|Win32">
<Tool
Name="GeneralTool"
OutputDirectory=".\Release"
IntermediateDirectory="c:\spu2ghz_temp\"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
WholeProgramOptimization="1"/>
<Tool
Name="PreBuildEventTool"/>
<Tool
Name="CustomTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="MidlCmplrTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="1"
TypeLibraryName=".\Release/SPU2ghz.tlb"
HeaderFileName=""/>
<Tool
Name="CppCmplrTool"
Optimization="2"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
PreprocessorDefinitions="NDEBUG;__WIN32__;__MSCW32__;WIN32;_WINDOWS;_USRDLL;SPU2GHZ_EXPORTS;_VS2005;_CRT_SECURE_NO_DEPRECATE"
StringPooling="true"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
EnableEnhancedInstructionSet="2"
FloatingPointModel="2"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\Release/SPU2ghz.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
Detect64BitPortabilityProblems="true"
CompileAs="0"
EnablePREfast="true"/>
<Tool
Name="VCManagedResourceCompilerTool"/>
<Tool
Name="ResCmplrTool"
PreprocessorDefinitions="NDEBUG"
Culture="3082"/>
<Tool
Name="PreLinkEventTool"/>
<Tool
Name="LinkerTool"
AdditionalOptions="/delayload:fmod.dll"
AdditionalDependencies="winmm.lib ./fmodapi/lib/fmodvc.lib dsound.lib"
OutputFile="F:\Pcsx2\plugins\SPU2ghz.dll"
LinkIncremental="1"
SuppressStartupBanner="true"
ModuleDefinitionFile=".\SPU2ghz.def"
GenerateDebugInformation="true"
ProgramDatabaseFile=".\Release/SPU2ghz.pdb"
ImportLibrary=".\Release/SPU2ghz.lib"
TargetMachine="1"/>
<Tool
Name="VCALinkTool"/>
<Tool
Name="VCManifestTool"/>
<Tool
Name="VCXDCMakeTool"/>
<Tool
Name="BscMakeTool"
SuppressStartupBanner="true"
OutputFile=""/>
<Tool
Name="VCFxCopTool"/>
<Tool
Name="VCAppVerifierTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="PostBuildEventTool"/>
</Configuration>
<Configuration
Name="Debug|Win32">
<Tool
Name="GeneralTool"
OutputDirectory=".\Debug"
IntermediateDirectory=".\Debug"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"/>
<Tool
Name="PreBuildEventTool"/>
<Tool
Name="CustomTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="MidlCmplrTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="1"
TypeLibraryName=".\Debug/SPU2ghz.tlb"
HeaderFileName=""/>
<Tool
Name="CppCmplrTool"
Optimization="0"
PreprocessorDefinitions="_DEBUG;__WIN32__;__MSCW32__;WIN32;_WINDOWS;_USRDLL;SPU2GHZ_EXPORTS;_VS2005;_CRT_SECURE_NO_DEPRECATE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\Debug/SPU2ghz.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="4"/>
<Tool
Name="VCManagedResourceCompilerTool"/>
<Tool
Name="ResCmplrTool"
PreprocessorDefinitions="_DEBUG"
Culture="3082"/>
<Tool
Name="PreLinkEventTool"/>
<Tool
Name="LinkerTool"
AdditionalDependencies="winmm.lib ./fmodapi/lib/fmodvc.lib dsound.lib"
OutputFile="F:\Pcsx2\plugins\SPU2ghz.dll"
LinkIncremental="2"
SuppressStartupBanner="true"
ModuleDefinitionFile=".\SPU2ghz.def"
GenerateDebugInformation="true"
ProgramDatabaseFile="\Pcsx2\plugins\SPU2ghz.pdb"
ImportLibrary=".\Debug/SPU2ghz1.lib"
TargetMachine="1"/>
<Tool
Name="VCALinkTool"/>
<Tool
Name="VCManifestTool"/>
<Tool
Name="VCXDCMakeTool"/>
<Tool
Name="BscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\Debug/SPU2ghz.bsc"/>
<Tool
Name="VCFxCopTool"/>
<Tool
Name="VCAppVerifierTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="PostBuildEventTool"/>
</Configuration>
<Configuration
Name="Public Release|Win32">
<Tool
Name="GeneralTool"
OutputDirectory="$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
WholeProgramOptimization="1"/>
<Tool
Name="PreBuildEventTool"/>
<Tool
Name="CustomTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="MidlCmplrTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="1"
TypeLibraryName=".\Release/SPU2ghz.tlb"
HeaderFileName=""/>
<Tool
Name="CppCmplrTool"
Optimization="2"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
PreprocessorDefinitions="NDEBUG;PUBLIC;__WIN32__;__MSCW32__;WIN32;_WINDOWS;_USRDLL;SPU2GHZ_EXPORTS;_VS2005;_CRT_SECURE_NO_DEPRECATE"
StringPooling="true"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
EnableEnhancedInstructionSet="1"
FloatingPointModel="2"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=""
AssemblerListingLocation="$(IntDir)\"
ObjectFile="$(IntDir)\"
ProgramDataBaseFileName="$(ConfigurationName)"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
Detect64BitPortabilityProblems="true"
CompileAs="0"
EnablePREfast="true"/>
<Tool
Name="VCManagedResourceCompilerTool"/>
<Tool
Name="ResCmplrTool"
PreprocessorDefinitions="NDEBUG"
Culture="3082"/>
<Tool
Name="PreLinkEventTool"/>
<Tool
Name="LinkerTool"
AdditionalDependencies="winmm.lib ./fmodapi/lib/fmodvc.lib dsound.lib"
OutputFile=".\bin\SPU2ghz.dll"
LinkIncremental="1"
SuppressStartupBanner="true"
ModuleDefinitionFile=".\SPU2ghz.def"
GenerateDebugInformation="false"
ProgramDatabaseFile=""
StripPrivateSymbols=".\bin\spu2ghz.pdb"
ImportLibrary=".\Release/SPU2ghz.lib"
TargetMachine="1"/>
<Tool
Name="VCALinkTool"/>
<Tool
Name="VCManifestTool"/>
<Tool
Name="VCXDCMakeTool"/>
<Tool
Name="BscMakeTool"
SuppressStartupBanner="true"
OutputFile=""/>
<Tool
Name="VCFxCopTool"/>
<Tool
Name="VCAppVerifierTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="PostBuildEventTool"
Description="Building Release RAR..."
CommandLine=".\mkrelease.cmd"/>
</Configuration>
<Configuration
Name="Debug SSE2|Win32">
<Tool
Name="GeneralTool"
OutputDirectory="$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"/>
<Tool
Name="PreBuildEventTool"/>
<Tool
Name="CustomTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="MidlCmplrTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="1"
TypeLibraryName=".\Debug/SPU2ghz.tlb"
HeaderFileName=""/>
<Tool
Name="CppCmplrTool"
Optimization="0"
PreprocessorDefinitions="_DEBUG;__WIN32__;__MSCW32__;WIN32;_WINDOWS;_USRDLL;SPU2GHZ_EXPORTS;_VS2005;_CRT_SECURE_NO_DEPRECATE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
EnableFunctionLevelLinking="true"
EnableEnhancedInstructionSet="2"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\Debug/SPU2ghz.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="4"/>
<Tool
Name="VCManagedResourceCompilerTool"/>
<Tool
Name="ResCmplrTool"
PreprocessorDefinitions="_DEBUG"
Culture="3082"/>
<Tool
Name="PreLinkEventTool"/>
<Tool
Name="LinkerTool"
AdditionalDependencies="winmm.lib ./fmodapi/lib/fmodvc.lib dsound.lib"
OutputFile="F:\Pcsx2\plugins\SPU2ghz.dll"
LinkIncremental="2"
SuppressStartupBanner="true"
ModuleDefinitionFile=".\SPU2ghz.def"
GenerateDebugInformation="true"
ProgramDatabaseFile="\Pcsx2\plugins\SPU2ghz.pdb"
ImportLibrary=".\Debug/SPU2ghz1.lib"
TargetMachine="1"/>
<Tool
Name="VCALinkTool"/>
<Tool
Name="VCManifestTool"/>
<Tool
Name="VCXDCMakeTool"/>
<Tool
Name="BscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\Debug/SPU2ghz.bsc"/>
<Tool
Name="VCFxCopTool"/>
<Tool
Name="VCAppVerifierTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="PostBuildEventTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="h;hpp;cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
<File
RelativePath=".\utf8.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
</File>
<File
RelativePath=".\utf8.h">
</File>
<Filter
Name="mixer">
<File
RelativePath=".\lowpass.cpp">
</File>
<File
RelativePath=".\lowpass.h">
</File>
<File
RelativePath=".\mixer.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug SSE2|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
</File>
<File
RelativePath="mixer.h">
</File>
</Filter>
<Filter
Name="debug">
<File
RelativePath=".\debug.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug SSE2|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
</File>
<File
RelativePath="debug.h">
</File>
<File
RelativePath=".\spu2replay.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
</File>
<File
RelativePath=".\spu2replay.h">
</File>
<File
RelativePath=".\wavedump_wav.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Output Modules">
<File
RelativePath=".\sndout.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug SSE2|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
</File>
<File
RelativePath="sndout.h">
</File>
<Filter
Name="asio">
<File
RelativePath=".\asio\asio.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
</File>
<File
RelativePath=".\asio\asio.h">
</File>
<File
RelativePath=".\asio\ASIOConvertSamples.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
</File>
<File
RelativePath=".\asio\ASIOConvertSamples.h">
</File>
<File
RelativePath=".\asio\asiodrivers.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
</File>
<File
RelativePath=".\asio\asiodrivers.h">
</File>
<File
RelativePath=".\asio\asiolist.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
</File>
<File
RelativePath=".\asio\asiolist.h">
</File>
<File
RelativePath=".\asioout.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
CompileAs="0"/>
</FileConfiguration>
</File>
<File
RelativePath=".\asio\asiosys.h">
</File>
<File
RelativePath=".\asio\ginclude.h">
</File>
</Filter>
<Filter
Name="FMod">
<File
RelativePath=".\fmodout.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug SSE2|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="waveOut">
<File
RelativePath=".\waveout.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug SSE2|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="XAudio2">
<File
RelativePath=".\xaudio2out.cpp">
</File>
</Filter>
<Filter
Name="DSound">
<File
RelativePath=".\dsound51.cpp">
</File>
<File
RelativePath=".\dsoundout.cpp">
</File>
</Filter>
</Filter>
<Filter
Name="decoder">
<File
RelativePath=".\decoder.cpp">
</File>
<File
RelativePath=".\spdif.h">
</File>
<Filter
Name="ac3(a/52)">
<File
RelativePath=".\liba52\a52.h">
</File>
<File
RelativePath=".\liba52\a52_internal.h">
</File>
<File
RelativePath=".\liba52\attributes.h">
</File>
<File
RelativePath=".\liba52\bit_allocate.c">
</File>
<File
RelativePath=".\liba52\bitstream.c">
</File>
<File
RelativePath=".\liba52\bitstream.h">
</File>
<File
RelativePath=".\liba52\downmix.c">
</File>
<File
RelativePath=".\liba52\imdct.c">
</File>
<File
RelativePath=".\liba52\mm_accel.h">
</File>
<File
RelativePath=".\liba52\parse.c">
</File>
<File
RelativePath=".\liba52\tables.h">
</File>
<File
RelativePath=".\liba52\tendra.h">
</File>
</Filter>
</Filter>
<Filter
Name="dma">
<File
RelativePath=".\dma.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug SSE2|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
</File>
<File
RelativePath="dma.h">
</File>
</Filter>
<Filter
Name="resources">
<File
RelativePath=".\resource.h">
</File>
<File
RelativePath="SPU2ghz.def">
</File>
<File
RelativePath=".\SPU2ghz.rc">
</File>
</Filter>
<Filter
Name="system">
<File
RelativePath="defs.h">
</File>
<File
RelativePath="PS2Edefs.h">
</File>
<File
RelativePath="PS2Etypes.h">
</File>
<File
RelativePath="regs.h">
</File>
<File
RelativePath=".\regtable.h">
</File>
<File
RelativePath=".\spu2.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug SSE2|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
</File>
<File
RelativePath="spu2.h">
</File>
</Filter>
<Filter
Name="config">
<File
RelativePath=".\config.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
<FileConfiguration
Name="Public Release|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"
CompileAs="0"/>
</FileConfiguration>
<FileConfiguration
Name="Debug SSE2|Win32">
<Tool
Name="CppCmplrTool"
UsePrecompiledHeader="0"
BrowseInformation="1"/>
</FileConfiguration>
</File>
<File
RelativePath="config.h">
</File>
</Filter>
</Filter>
<Filter
Name="Documents">
<File
RelativePath=".\CHANGELOG.TXT">
</File>
<File
RelativePath="LGPL.txt">
</File>
<File
RelativePath="License.txt">
</File>
<File
RelativePath=".\TODO.txt">
</File>
</Filter>
<File
RelativePath=".\delayimp.lib">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,33 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{EAF909A5-FA59-4C3D-9431-0FCC20D5BCF9}") = "SPU2ghz_vs2005", "SPU2ghz_intel.icproj", "{09981E32-E8D9-465E-A5D2-4077FE49459B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug SSE2|Win32 = Debug SSE2|Win32
Debug|Win32 = Debug|Win32
Public Release|Win32 = Public Release|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{09981E32-E8D9-465E-A5D2-4077FE49459B}.Debug SSE2|Win32.ActiveCfg = Debug SSE2|Win32
{09981E32-E8D9-465E-A5D2-4077FE49459B}.Debug SSE2|Win32.Build.0 = Debug SSE2|Win32
{09981E32-E8D9-465E-A5D2-4077FE49459B}.Debug|Win32.ActiveCfg = Debug|Win32
{09981E32-E8D9-465E-A5D2-4077FE49459B}.Debug|Win32.Build.0 = Debug|Win32
{09981E32-E8D9-465E-A5D2-4077FE49459B}.Public Release|Win32.ActiveCfg = Public Release|Win32
{09981E32-E8D9-465E-A5D2-4077FE49459B}.Public Release|Win32.Build.0 = Public Release|Win32
{09981E32-E8D9-465E-A5D2-4077FE49459B}.Release|Win32.ActiveCfg = Release|Win32
{09981E32-E8D9-465E-A5D2-4077FE49459B}.Release|Win32.Build.0 = Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|Win32.Build.0 = Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|Win32.ActiveCfg = Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Public Release|Win32.Build.0 = Public Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Public Release|Win32.ActiveCfg = Public Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug|Win32.Build.0 = Debug|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug|Win32.ActiveCfg = Debug|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug SSE2|Win32.Build.0 = Debug SSE2|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug SSE2|Win32.ActiveCfg = Debug SSE2|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPU2ghz_vs2005", "SPU2ghz_vs2005.vcproj", "{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug SSE2|Win32 = Debug SSE2|Win32
Debug|Win32 = Debug|Win32
Public Release|Win32 = Public Release|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug SSE2|Win32.ActiveCfg = Debug SSE2|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug SSE2|Win32.Build.0 = Debug SSE2|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug|Win32.ActiveCfg = Debug|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug|Win32.Build.0 = Debug|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Public Release|Win32.ActiveCfg = Public Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Public Release|Win32.Build.0 = Public Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|Win32.ActiveCfg = Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPU2ghz_vs2005", "SPU2ghz_vs2005_64.vcproj", "{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug|x64.ActiveCfg = Debug|x64
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug|x64.Build.0 = Debug|x64
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|x64.ActiveCfg = Release|x64
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,457 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="SPU2ghz_vs2005"
ProjectGUID="{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}"
RootNamespace="SPU2ghz_vs2005"
>
<Platforms>
<Platform
Name="x64"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Release|x64"
OutputDirectory="x64\$(ConfigurationName)"
IntermediateDirectory="x64\$(ConfigurationName)"
ConfigurationType="2"
InheritedPropertySheets="..\..\..\..\..\Archivos de programa\Microsoft Visual Studio 8\VC\VCProjectDefaults\UpgradeFromVC60.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
WholeProgramOptimization="0"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="3"
TypeLibraryName=".\Release/SPU2ghz.tlb"
HeaderFileName=""
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/analyze"
Optimization="2"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
WholeProgramOptimization="false"
PreprocessorDefinitions="NDEBUG;__WIN64__;_WINDOWS;_USRDLL;SPU2GHZ_EXPORTS;_VS2005;WIN64"
StringPooling="true"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="true"
EnableEnhancedInstructionSet="2"
FloatingPointModel="2"
UsePrecompiledHeader="0"
PrecompiledHeaderFile="x64\$(ConfigurationName)/SPU2ghz64.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
Detect64BitPortabilityProblems="true"
CompileAs="1"
EnablePREfast="false"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="3082"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="winmm.lib ./fmodapi/lib/fmod64vc.lib"
OutputFile="./bin/SPU2ghz64.dll"
LinkIncremental="1"
SuppressStartupBanner="true"
ModuleDefinitionFile=".\SPU2ghz.def"
ProgramDatabaseFile="x64\$(ConfigurationName)\SPU2ghz.pdb"
ImportLibrary="x64\$(ConfigurationName)/SPU2ghz.lib"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\Release/SPU2ghz.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|x64"
OutputDirectory="x64\$(ConfigurationName)"
IntermediateDirectory="x64\$(ConfigurationName)"
ConfigurationType="2"
InheritedPropertySheets="..\..\..\..\..\Archivos de programa\Microsoft Visual Studio 8\VC\VCProjectDefaults\UpgradeFromVC60.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="true"
SuppressStartupBanner="true"
TargetEnvironment="3"
TypeLibraryName=".\Debug/SPU2ghz.tlb"
HeaderFileName=""
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="_DEBUG;__WIN64__;_WINDOWS;_USRDLL;SPU2GHZ_EXPORTS;WIN64"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\Debug/SPU2ghz.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="3082"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="winmm.lib ./fmodapi/lib/fmod64vc.lib"
OutputFile="c:\coses\emulation\ps2\pcsx2\plugins\SPU2ghz64.dll"
LinkIncremental="2"
SuppressStartupBanner="true"
ModuleDefinitionFile=".\SPU2ghz.def"
GenerateDebugInformation="true"
ProgramDatabaseFile=".\Debug/SPU2ghz1.pdb"
ImportLibrary=".\Debug/SPU2ghz1.lib"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\Debug/SPU2ghz.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
>
<File
RelativePath=".\asioout.cpp"
>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\config.cpp"
>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\debug.cpp"
>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\dma.cpp"
>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\fmodout.cpp"
>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\mixer.cpp"
>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\sndout.cpp"
>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\spu2.cpp"
>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\SPU2ghz.def"
>
</File>
<File
RelativePath=".\SPU2ghz.rc"
>
</File>
<File
RelativePath=".\spu2replay.cpp"
>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\utf8.cpp"
>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\wavedump_wav.cpp"
>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\waveout.cpp"
>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
CompileAs="2"
/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl"
>
<File
RelativePath=".\config.h"
>
</File>
<File
RelativePath=".\debug.h"
>
</File>
<File
RelativePath=".\defs.h"
>
</File>
<File
RelativePath=".\dma.h"
>
</File>
<File
RelativePath=".\mixer.h"
>
</File>
<File
RelativePath=".\PS2Edefs.h"
>
</File>
<File
RelativePath=".\PS2Etypes.h"
>
</File>
<File
RelativePath=".\regs.h"
>
</File>
<File
RelativePath=".\resource.h"
>
</File>
<File
RelativePath=".\sndout.h"
>
</File>
<File
RelativePath=".\spu2.h"
>
</File>
<File
RelativePath=".\spu2replay.h"
>
</File>
<File
RelativePath=".\utf8.h"
>
</File>
</Filter>
<Filter
Name="Documents"
>
<File
RelativePath="LGPL.txt"
>
</File>
<File
RelativePath="License.txt"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,26 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SPU2ghz_vs2008", "SPU2ghz_vs2008.vcproj", "{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug SSE2|Win32 = Debug SSE2|Win32
Debug|Win32 = Debug|Win32
Public Release|Win32 = Public Release|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug SSE2|Win32.ActiveCfg = Debug SSE2|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug SSE2|Win32.Build.0 = Debug SSE2|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug|Win32.ActiveCfg = Debug|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Debug|Win32.Build.0 = Debug|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Public Release|Win32.ActiveCfg = Public Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Public Release|Win32.Build.0 = Public Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|Win32.ActiveCfg = Release|Win32
{5307BBB7-EBB9-4AA4-8CB6-A94EC473C8C4}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,350 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Win32 version of the AMD 3DNow! optimized routines for AMD K6-2/Athlon
/// processors. All 3DNow! optimized functions have been gathered into this
/// single source code file, regardless to their class or original source code
/// file, in order to ease porting the library to other compiler and processor
/// platforms.
///
/// By the way; the performance gain depends heavily on the CPU generation: On
/// K6-2 these routines provided speed-up of even 2.4 times, while on Athlon the
/// difference to the original routines stayed at unremarkable 8%! Such a small
/// improvement on Athlon is due to 3DNow can perform only two operations in
/// parallel, and obviously also the Athlon FPU is doing a very good job with
/// the standard C floating point routines! Here these routines are anyway,
/// although it might not be worth the effort to convert these to GCC platform,
/// for Athlon CPU at least. The situation is different regarding the SSE
/// optimizations though, thanks to the four parallel operations of SSE that
/// already make a difference.
///
/// This file is to be compiled in Windows platform with Microsoft Visual C++
/// Compiler. Please see '3dnow_gcc.cpp' for the gcc compiler version for all
/// GNU platforms (if file supplied).
///
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
/// 6.0 processor pack" update to support 3DNow! instruction set. The update is
/// available for download at Microsoft Developers Network, see here:
/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx
///
/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and
/// perform a search with keywords "processor pack".
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.10 $
//
// $Id: 3dnow_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include "cpu_detect.h"
#include "STTypes.h"
#ifndef _WIN32
#error "wrong platform - this source code file is exclusively for Win32 platform"
#endif
using namespace soundtouch;
#ifdef ALLOW_3DNOW
// 3DNow! routines available only with float sample type
//////////////////////////////////////////////////////////////////////////////
//
// implementation of 3DNow! optimized functions of class 'TDStretch3DNow'
//
//////////////////////////////////////////////////////////////////////////////
#include "TDStretch.h"
#include <limits.h>
// these are declared in 'TDStretch.cpp'
extern int scanOffsets[4][24];
// Calculates cross correlation of two buffers
double TDStretch3DNow::calcCrossCorrStereo(const float *pV1, const float *pV2) const
{
uint overlapLengthLocal = overlapLength;
float corr;
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
/*
c-pseudocode:
corr = 0;
for (i = 0; i < overlapLength / 4; i ++)
{
corr += pV1[0] * pV2[0];
pV1[1] * pV2[1];
pV1[2] * pV2[2];
pV1[3] * pV2[3];
pV1[4] * pV2[4];
pV1[5] * pV2[5];
pV1[6] * pV2[6];
pV1[7] * pV2[7];
pV1 += 8;
pV2 += 8;
}
*/
_asm
{
// give prefetch hints to CPU of what data are to be needed soonish.
// give more aggressive hints on pV1 as that changes more between different calls
// while pV2 stays the same.
prefetch [pV1]
prefetch [pV2]
prefetch [pV1 + 32]
mov eax, dword ptr pV2
mov ebx, dword ptr pV1
pxor mm0, mm0
mov ecx, overlapLengthLocal
shr ecx, 2 // div by four
loop1:
movq mm1, [eax]
prefetch [eax + 32] // give a prefetch hint to CPU what data are to be needed soonish
pfmul mm1, [ebx]
prefetch [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish
movq mm2, [eax + 8]
pfadd mm0, mm1
pfmul mm2, [ebx + 8]
movq mm3, [eax + 16]
pfadd mm0, mm2
pfmul mm3, [ebx + 16]
movq mm4, [eax + 24]
pfadd mm0, mm3
pfmul mm4, [ebx + 24]
add eax, 32
pfadd mm0, mm4
add ebx, 32
dec ecx
jnz loop1
// add halfs of mm0 together and return the result.
// note: mm1 is used as a dummy parameter only, we actually don't care about it's value
pfacc mm0, mm1
movd corr, mm0
femms
}
return corr;
}
//////////////////////////////////////////////////////////////////////////////
//
// implementation of 3DNow! optimized functions of class 'FIRFilter'
//
//////////////////////////////////////////////////////////////////////////////
#include "FIRFilter.h"
FIRFilter3DNow::FIRFilter3DNow() : FIRFilter()
{
filterCoeffsUnalign = NULL;
}
FIRFilter3DNow::~FIRFilter3DNow()
{
delete[] filterCoeffsUnalign;
}
// (overloaded) Calculates filter coefficients for 3DNow! routine
void FIRFilter3DNow::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor)
{
uint i;
float fDivider;
FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
// Scale the filter coefficients so that it won't be necessary to scale the filtering result
// also rearrange coefficients suitably for 3DNow!
// Ensure that filter coeffs array is aligned to 16-byte boundary
delete[] filterCoeffsUnalign;
filterCoeffsUnalign = new float[2 * newLength + 4];
filterCoeffsAlign = (float *)(((uint)filterCoeffsUnalign + 15) & -16);
fDivider = (float)resultDivider;
// rearrange the filter coefficients for mmx routines
for (i = 0; i < newLength; i ++)
{
filterCoeffsAlign[2 * i + 0] =
filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider;
}
}
// 3DNow!-optimized version of the filter routine for stereo sound
uint FIRFilter3DNow::evaluateFilterStereo(float *dest, const float *src, const uint numSamples) const
{
float *filterCoeffsLocal = filterCoeffsAlign;
uint count = (numSamples - length) & -2;
uint lengthLocal = length / 4;
assert(length != 0);
assert(count % 2 == 0);
/* original code:
double suml1, suml2;
double sumr1, sumr2;
uint i, j;
for (j = 0; j < count; j += 2)
{
const float *ptr;
suml1 = sumr1 = 0.0;
suml2 = sumr2 = 0.0;
ptr = src;
filterCoeffsLocal = filterCoeffs;
for (i = 0; i < lengthLocal; i ++)
{
// unroll loop for efficiency.
suml1 += ptr[0] * filterCoeffsLocal[0] +
ptr[2] * filterCoeffsLocal[2] +
ptr[4] * filterCoeffsLocal[4] +
ptr[6] * filterCoeffsLocal[6];
sumr1 += ptr[1] * filterCoeffsLocal[1] +
ptr[3] * filterCoeffsLocal[3] +
ptr[5] * filterCoeffsLocal[5] +
ptr[7] * filterCoeffsLocal[7];
suml2 += ptr[8] * filterCoeffsLocal[0] +
ptr[10] * filterCoeffsLocal[2] +
ptr[12] * filterCoeffsLocal[4] +
ptr[14] * filterCoeffsLocal[6];
sumr2 += ptr[9] * filterCoeffsLocal[1] +
ptr[11] * filterCoeffsLocal[3] +
ptr[13] * filterCoeffsLocal[5] +
ptr[15] * filterCoeffsLocal[7];
ptr += 16;
filterCoeffsLocal += 8;
}
dest[0] = (float)suml1;
dest[1] = (float)sumr1;
dest[2] = (float)suml2;
dest[3] = (float)sumr2;
src += 4;
dest += 4;
}
*/
_asm
{
mov eax, dword ptr dest
mov ebx, dword ptr src
mov edx, count
shr edx, 1
loop1:
// "outer loop" : during each round 2*2 output samples are calculated
prefetch [ebx] // give a prefetch hint to CPU what data are to be needed soonish
prefetch [filterCoeffsLocal] // give a prefetch hint to CPU what data are to be needed soonish
mov esi, ebx
mov edi, filterCoeffsLocal
pxor mm0, mm0
pxor mm1, mm1
mov ecx, lengthLocal
loop2:
// "inner loop" : during each round four FIR filter taps are evaluated for 2*2 output samples
movq mm2, [edi]
movq mm3, mm2
prefetch [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish
pfmul mm2, [esi]
prefetch [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish
pfmul mm3, [esi + 8]
movq mm4, [edi + 8]
movq mm5, mm4
pfadd mm0, mm2
pfmul mm4, [esi + 8]
pfadd mm1, mm3
pfmul mm5, [esi + 16]
movq mm2, [edi + 16]
movq mm6, mm2
pfadd mm0, mm4
pfmul mm2, [esi + 16]
pfadd mm1, mm5
pfmul mm6, [esi + 24]
movq mm3, [edi + 24]
movq mm7, mm3
pfadd mm0, mm2
pfmul mm3, [esi + 24]
pfadd mm1, mm6
pfmul mm7, [esi + 32]
add esi, 32
pfadd mm0, mm3
add edi, 32
pfadd mm1, mm7
dec ecx
jnz loop2
movq [eax], mm0
add ebx, 16
movq [eax + 8], mm1
add eax, 16
dec edx
jnz loop1
femms
}
return count;
}
#endif // ALLOW_3DNOW

View File

@ -0,0 +1,184 @@
////////////////////////////////////////////////////////////////////////////////
///
/// FIR low-pass (anti-alias) filter with filter coefficient design routine and
/// MMX optimization.
///
/// Anti-alias filter is used to prevent folding of high frequencies when
/// transposing the sample rate with interpolation.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.9 $
//
// $Id: AAFilter.cpp,v 1.9 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <memory.h>
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include "AAFilter.h"
#include "FIRFilter.h"
using namespace soundtouch;
#define PI 3.141592655357989
#define TWOPI (2 * PI)
/*****************************************************************************
*
* Implementation of the class 'AAFilter'
*
*****************************************************************************/
AAFilter::AAFilter(const uint length)
{
pFIR = FIRFilter::newInstance();
cutoffFreq = 0.5;
setLength(length);
}
AAFilter::~AAFilter()
{
delete pFIR;
}
// Sets new anti-alias filter cut-off edge frequency, scaled to
// sampling frequency (nyquist frequency = 0.5).
// The filter will cut frequencies higher than the given frequency.
void AAFilter::setCutoffFreq(const double newCutoffFreq)
{
cutoffFreq = newCutoffFreq;
calculateCoeffs();
}
// Sets number of FIR filter taps
void AAFilter::setLength(const uint newLength)
{
length = newLength;
calculateCoeffs();
}
// Calculates coefficients for a low-pass FIR filter using Hamming window
void AAFilter::calculateCoeffs()
{
uint i;
double cntTemp, temp, tempCoeff,h, w;
double fc2, wc;
double scaleCoeff, sum;
double *work;
SAMPLETYPE *coeffs;
assert(length > 0);
assert(length % 4 == 0);
assert(cutoffFreq >= 0);
assert(cutoffFreq <= 0.5);
work = new double[length];
coeffs = new SAMPLETYPE[length];
fc2 = 2.0 * cutoffFreq;
wc = PI * fc2;
tempCoeff = TWOPI / (double)length;
sum = 0;
for (i = 0; i < length; i ++)
{
cntTemp = (double)i - (double)(length / 2);
temp = cntTemp * wc;
if (temp != 0)
{
h = fc2 * sin(temp) / temp; // sinc function
}
else
{
h = 1.0;
}
w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window
temp = w * h;
work[i] = temp;
// calc net sum of coefficients
sum += temp;
}
// ensure the sum of coefficients is larger than zero
assert(sum > 0);
// ensure we've really designed a lowpass filter...
assert(work[length/2] > 0);
assert(work[length/2 + 1] > -1e-6);
assert(work[length/2 - 1] > -1e-6);
// Calculate a scaling coefficient in such a way that the result can be
// divided by 16384
scaleCoeff = 16384.0f / sum;
for (i = 0; i < length; i ++)
{
// scale & round to nearest integer
temp = work[i] * scaleCoeff;
temp += (temp >= 0) ? 0.5 : -0.5;
// ensure no overfloods
assert(temp >= -32768 && temp <= 32767);
coeffs[i] = (SAMPLETYPE)temp;
}
// Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384
pFIR->setCoefficients(coeffs, length, 14);
delete[] work;
delete[] coeffs;
}
// Applies the filter to the given sequence of samples.
// Note : The amount of outputted samples is by value of 'filter length'
// smaller than the amount of input samples.
uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
{
return pFIR->evaluate(dest, src, numSamples, numChannels);
}
uint AAFilter::getLength() const
{
return pFIR->getLength();
}

View File

@ -0,0 +1,91 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
/// while maintaining the original pitch by using a time domain WSOLA-like method
/// with several performance-increasing tweaks.
///
/// Anti-alias filter is used to prevent folding of high frequencies when
/// transposing the sample rate with interpolation.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.10 $
//
// $Id: AAFilter.h,v 1.10 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef AAFilter_H
#define AAFilter_H
#include "STTypes.h"
namespace soundtouch
{
class AAFilter
{
protected:
class FIRFilter *pFIR;
/// Low-pass filter cut-off frequency, negative = invalid
double cutoffFreq;
/// num of filter taps
uint length;
/// Calculate the FIR coefficients realizing the given cutoff-frequency
void calculateCoeffs();
public:
AAFilter(uint length);
~AAFilter();
/// Sets new anti-alias filter cut-off edge frequency, scaled to sampling
/// frequency (nyquist frequency = 0.5). The filter will cut off the
/// frequencies than that.
void setCutoffFreq(double newCutoffFreq);
/// Sets number of FIR filter taps, i.e. ~filter complexity
void setLength(uint newLength);
uint getLength() const;
/// Applies the filter to the given sequence of samples.
/// Note : The amount of outputted samples is by value of 'filter length'
/// smaller than the amount of input samples.
uint evaluate(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples,
uint numChannels) const;
};
}
#endif

View File

@ -0,0 +1,159 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Beats-per-minute (BPM) detection routine.
///
/// The beat detection algorithm works as follows:
/// - Use function 'inputSamples' to input a chunks of samples to the class for
/// analysis. It's a good idea to enter a large sound file or stream in smallish
/// chunks of around few kilosamples in order not to extinguish too much RAM memory.
/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden,
/// which is basically ok as low (bass) frequencies mostly determine the beat rate.
/// Simple averaging is used for anti-alias filtering because the resulting signal
/// quality isn't of that high importance.
/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by
/// taking absolute value that's smoothed by sliding average. Signal levels that
/// are below a couple of times the general RMS amplitude level are cut away to
/// leave only notable peaks there.
/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term
/// autocorrelation function of the enveloped signal.
/// - After whole sound data file has been analyzed as above, the bpm level is
/// detected by function 'getBpm' that finds the highest peak of the autocorrelation
/// function, calculates it's precise location and converts this reading to bpm's.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.5 $
//
// $Id: BPMDetect.h,v 1.5 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _BPMDetect_H_
#define _BPMDetect_H_
#include "STTypes.h"
#include "FIFOSampleBuffer.h"
/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit.
#define MIN_BPM 45
/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit.
#define MAX_BPM 230
/// Class for calculating BPM rate for audio data.
class BPMDetect
{
protected:
/// Auto-correlation accumulator bins.
float *xcorr;
/// Amplitude envelope sliding average approximation level accumulator
float envelopeAccu;
/// RMS volume sliding average approximation level accumulator
float RMSVolumeAccu;
/// Sample average counter.
int decimateCount;
/// Sample average accumulator for FIFO-like decimation.
soundtouch::LONG_SAMPLETYPE decimateSum;
/// Decimate sound by this coefficient to reach approx. 500 Hz.
int decimateBy;
/// Auto-correlation window length
int windowLen;
/// Number of channels (1 = mono, 2 = stereo)
int channels;
/// sample rate
int sampleRate;
/// Beginning of auto-correlation window: Autocorrelation isn't being updated for
/// the first these many correlation bins.
int windowStart;
/// FIFO-buffer for decimated processing samples.
soundtouch::FIFOSampleBuffer *buffer;
/// Initialize the class for processing.
void init(int numChannels, int sampleRate);
/// Updates auto-correlation function for given number of decimated samples that
/// are read from the internal 'buffer' pipe (samples aren't removed from the pipe
/// though).
void updateXCorr(int process_samples /// How many samples are processed.
);
/// Decimates samples to approx. 500 Hz.
///
/// \return Number of output samples.
int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer
const soundtouch::SAMPLETYPE *src, ///< Source sample buffer
int numsamples ///< Number of source samples.
);
/// Calculates amplitude envelope for the buffer of samples.
/// Result is output to 'samples'.
void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer
int numsamples ///< Number of samples in buffer
);
public:
/// Constructor.
BPMDetect(int numChannels, ///< Number of channels in sample data.
int sampleRate ///< Sample rate in Hz.
);
/// Destructor.
virtual ~BPMDetect();
/// Inputs a block of samples for analyzing: Envelopes the samples and then
/// updates the autocorrelation estimation. When whole song data has been input
/// in smaller blocks using this function, read the resulting bpm with 'getBpm'
/// function.
///
/// Notice that data in 'samples' array can be disrupted in processing.
void inputSamples(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer
int numSamples ///< Number of samples in buffer
);
/// Analyzes the results and returns the BPM rate. Use this function to read result
/// after whole song data has been input to the class by consecutive calls of
/// 'inputSamples' function.
///
/// \return Beats-per-minute rate, or zero if detection failed.
float getBpm();
};
#endif // _BPMDetect_H_

View File

@ -0,0 +1,252 @@
////////////////////////////////////////////////////////////////////////////////
///
/// A buffer class for temporarily storaging sound samples, operates as a
/// first-in-first-out pipe.
///
/// Samples are added to the end of the sample buffer with the 'putSamples'
/// function, and are received from the beginning of the buffer by calling
/// the 'receiveSamples' function. The class automatically removes the
/// outputted samples from the buffer, as well as grows the buffer size
/// whenever necessary.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.11 $
//
// $Id: FIFOSampleBuffer.cpp,v 1.11 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <assert.h>
#include <stdexcept>
#include "FIFOSampleBuffer.h"
using namespace soundtouch;
// Constructor
FIFOSampleBuffer::FIFOSampleBuffer(uint numChannels)
{
sizeInBytes = 0; // reasonable initial value
buffer = NULL; //new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE)];
bufferUnaligned = NULL;
samplesInBuffer = 0;
bufferPos = 0;
channels = numChannels;
}
// destructor
FIFOSampleBuffer::~FIFOSampleBuffer()
{
delete[] bufferUnaligned;
}
// Sets number of channels, 1 = mono, 2 = stereo
void FIFOSampleBuffer::setChannels(const uint numChannels)
{
uint usedBytes;
usedBytes = channels * samplesInBuffer;
channels = numChannels;
samplesInBuffer = usedBytes / channels;
}
// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and
// zeroes this pointer by copying samples from the 'bufferPos' pointer
// location on to the beginning of the buffer.
void FIFOSampleBuffer::rewind()
{
if (bufferPos)
{
memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer);
bufferPos = 0;
}
}
// Adds 'numSamples' pcs of samples from the 'samples' memory position to
// the sample buffer.
void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint numSamples)
{
memcpy(ptrEnd(numSamples), samples, sizeof(SAMPLETYPE) * numSamples * channels);
samplesInBuffer += numSamples;
}
// Increases the number of samples in the buffer without copying any actual
// samples.
//
// This function is used to update the number of samples in the sample buffer
// when accessing the buffer directly with 'ptrEnd' function. Please be
// careful though!
void FIFOSampleBuffer::putSamples(uint numSamples)
{
uint req;
req = samplesInBuffer + numSamples;
ensureCapacity(req);
samplesInBuffer += numSamples;
}
// Returns a pointer to the end of the used part of the sample buffer (i.e.
// where the new samples are to be inserted). This function may be used for
// inserting new samples into the sample buffer directly. Please be careful!
//
// Parameter 'slackCapacity' tells the function how much free capacity (in
// terms of samples) there _at least_ should be, in order to the caller to
// succesfully insert all the required samples to the buffer. When necessary,
// the function grows the buffer size to comply with this requirement.
//
// When using this function as means for inserting new samples, also remember
// to increase the sample count afterwards, by calling the
// 'putSamples(numSamples)' function.
SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity)
{
ensureCapacity(samplesInBuffer + slackCapacity);
return buffer + samplesInBuffer * channels;
}
// Returns a pointer to the beginning of the currently non-outputted samples.
// This function is provided for accessing the output samples directly.
// Please be careful!
//
// When using this function to output samples, also remember to 'remove' the
// outputted samples from the buffer by calling the
// 'receiveSamples(numSamples)' function
SAMPLETYPE *FIFOSampleBuffer::ptrBegin() const
{
return buffer + bufferPos * channels;
}
// Ensures that the buffer has enought capacity, i.e. space for _at least_
// 'capacityRequirement' number of samples. The buffer is grown in steps of
// 4 kilobytes to eliminate the need for frequently growing up the buffer,
// as well as to round the buffer size up to the virtual memory page size.
void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement)
{
SAMPLETYPE *tempUnaligned, *temp;
if (capacityRequirement > getCapacity())
{
// enlarge the buffer in 4kbyte steps (round up to next 4k boundary)
sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & -4096;
assert(sizeInBytes % 2 == 0);
tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)];
if (tempUnaligned == NULL)
{
throw std::runtime_error("Couldn't allocate memory!\n");
}
temp = (SAMPLETYPE *)(((ulongptr)tempUnaligned + 15) & -16);
memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE));
delete[] bufferUnaligned;
buffer = temp;
bufferUnaligned = tempUnaligned;
bufferPos = 0;
}
else
{
// simply rewind the buffer (if necessary)
rewind();
}
}
// Returns the current buffer capacity in terms of samples
uint FIFOSampleBuffer::getCapacity() const
{
return sizeInBytes / (channels * sizeof(SAMPLETYPE));
}
// Returns the number of samples currently in the buffer
uint FIFOSampleBuffer::numSamples() const
{
return samplesInBuffer;
}
// Output samples from beginning of the sample buffer. Copies demanded number
// of samples to output and removes them from the sample buffer. If there
// are less than 'numsample' samples in the buffer, returns all available.
//
// Returns number of samples copied.
uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples)
{
uint num;
num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples;
memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num);
return receiveSamples(num);
}
// Removes samples from the beginning of the sample buffer without copying them
// anywhere. Used to reduce the number of samples in the buffer, when accessing
// the sample buffer with the 'ptrBegin' function.
uint FIFOSampleBuffer::receiveSamples(uint maxSamples)
{
if (maxSamples >= samplesInBuffer)
{
uint temp;
temp = samplesInBuffer;
samplesInBuffer = 0;
return temp;
}
samplesInBuffer -= maxSamples;
bufferPos += maxSamples;
return maxSamples;
}
// Returns nonzero if the sample buffer is empty
int FIFOSampleBuffer::isEmpty() const
{
return (samplesInBuffer == 0) ? 1 : 0;
}
// Clears the sample buffer
void FIFOSampleBuffer::clear()
{
samplesInBuffer = 0;
bufferPos = 0;
}

View File

@ -0,0 +1,174 @@
////////////////////////////////////////////////////////////////////////////////
///
/// A buffer class for temporarily storaging sound samples, operates as a
/// first-in-first-out pipe.
///
/// Samples are added to the end of the sample buffer with the 'putSamples'
/// function, and are received from the beginning of the buffer by calling
/// the 'receiveSamples' function. The class automatically removes the
/// output samples from the buffer as well as grows the storage size
/// whenever necessary.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.9 $
//
// $Id: FIFOSampleBuffer.h,v 1.9 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef FIFOSampleBuffer_H
#define FIFOSampleBuffer_H
#include "FIFOSamplePipe.h"
namespace soundtouch
{
/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes
/// care of storage size adjustment and data moving during input/output operations.
///
/// Notice that in case of stereo audio, one sample is considered to consist of
/// both channel data.
class FIFOSampleBuffer : public FIFOSamplePipe
{
private:
/// Sample buffer.
SAMPLETYPE *buffer;
// Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first
// 16-byte aligned location of this buffer
SAMPLETYPE *bufferUnaligned;
/// Sample buffer size in bytes
uint sizeInBytes;
/// How many samples are currently in buffer.
uint samplesInBuffer;
/// Channels, 1=mono, 2=stereo.
uint channels;
/// Current position pointer to the buffer. This pointer is increased when samples are
/// removed from the pipe so that it's necessary to actually rewind buffer (move data)
/// only new data when is put to the pipe.
uint bufferPos;
/// Rewind the buffer by moving data from position pointed by 'bufferPos' to real
/// beginning of the buffer.
void rewind();
/// Ensures that the buffer has capacity for at least this many samples.
void ensureCapacity(const uint capacityRequirement);
/// Returns current capacity.
uint getCapacity() const;
public:
/// Constructor
FIFOSampleBuffer(uint numChannels = 2 ///< Number of channels, 1=mono, 2=stereo.
///< Default is stereo.
);
/// destructor
~FIFOSampleBuffer();
/// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping!
///
/// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin() const;
/// Returns a pointer to the end of the used part of the sample buffer (i.e.
/// where the new samples are to be inserted). This function may be used for
/// inserting new samples into the sample buffer directly. Please be careful
/// not corrupt the book-keeping!
///
/// When using this function as means for inserting new samples, also remember
/// to increase the sample count afterwards, by calling the
/// 'putSamples(numSamples)' function.
SAMPLETYPE *ptrEnd(
uint slackCapacity ///< How much free capacity (in samples) there _at least_
///< should be so that the caller can succesfully insert the
///< desired samples to the buffer. If necessary, the function
///< grows the buffer size to comply with this requirement.
);
/// Adds 'numSamples' pcs of samples from the 'samples' memory position to
/// the sample buffer.
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
uint numSamples ///< Number of samples to insert.
);
/// Adjusts the book-keeping to increase number of samples in the buffer without
/// copying any actual samples.
///
/// This function is used to update the number of samples in the sample buffer
/// when accessing the buffer directly with 'ptrEnd' function. Please be
/// careful though!
virtual void putSamples(uint numSamples ///< Number of samples been inserted.
);
/// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available.
///
/// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max.
);
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere.
///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
);
/// Returns number of samples currently available.
virtual uint numSamples() const;
/// Sets number of channels, 1 = mono, 2 = stereo.
void setChannels(uint numChannels);
/// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const;
/// Clears all the samples.
virtual void clear();
};
}
#endif

View File

@ -0,0 +1,217 @@
////////////////////////////////////////////////////////////////////////////////
///
/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound
/// samples by operating like a first-in-first-out pipe: New samples are fed
/// into one end of the pipe with the 'putSamples' function, and the processed
/// samples are received from the other end with the 'receiveSamples' function.
///
/// 'FIFOProcessor' : A base class for classes the do signal processing with
/// the samples while operating like a first-in-first-out pipe. When samples
/// are input with the 'putSamples' function, the class processes them
/// and moves the processed samples to the given 'output' pipe object, which
/// may be either another processing stage, or a fifo sample buffer object.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.8 $
//
// $Id: FIFOSamplePipe.h,v 1.8 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef FIFOSamplePipe_H
#define FIFOSamplePipe_H
#include <assert.h>
#include <stdlib.h>
#include "STTypes.h"
namespace soundtouch
{
/// Abstract base class for FIFO (first-in-first-out) sample processing classes.
class FIFOSamplePipe
{
public:
/// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping!
///
/// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin() const = 0;
/// Adds 'numSamples' pcs of samples from the 'samples' memory position to
/// the sample buffer.
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
uint numSamples ///< Number of samples to insert.
) = 0;
// Moves samples from the 'other' pipe instance to this instance.
void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data.
)
{
int oNumSamples = other.numSamples();
putSamples(other.ptrBegin(), oNumSamples);
other.receiveSamples(oNumSamples);
};
/// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available.
///
/// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max.
) = 0;
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere.
///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
) = 0;
/// Returns number of samples currently available.
virtual uint numSamples() const = 0;
// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const = 0;
/// Clears all the samples.
virtual void clear() = 0;
};
/// Base-class for sound processing routines working in FIFO principle. With this base
/// class it's easy to implement sound processing stages that can be chained together,
/// so that samples that are fed into beginning of the pipe automatically go through
/// all the processing stages.
///
/// When samples are input to this class, they're first processed and then put to
/// the FIFO pipe that's defined as output of this class. This output pipe can be
/// either other processing stage or a FIFO sample buffer.
class FIFOProcessor :public FIFOSamplePipe
{
protected:
/// Internal pipe where processed samples are put.
FIFOSamplePipe *output;
/// Sets output pipe.
void setOutPipe(FIFOSamplePipe *pOutput)
{
assert(output == NULL);
assert(pOutput != NULL);
output = pOutput;
}
/// Constructor. Doesn't define output pipe; it has to be set be
/// 'setOutPipe' function.
FIFOProcessor()
{
output = NULL;
}
/// Constructor. Configures output pipe.
FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe.
)
{
output = pOutput;
}
/// Destructor.
virtual ~FIFOProcessor()
{
}
/// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping!
///
/// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin() const
{
return output->ptrBegin();
}
public:
/// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available.
///
/// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max.
)
{
return output->receiveSamples(outBuffer, maxSamples);
}
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere.
///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
)
{
return output->receiveSamples(maxSamples);
}
/// Returns number of samples currently available.
virtual uint numSamples() const
{
return output->numSamples();
}
/// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const
{
return output->isEmpty();
}
};
}
#endif

View File

@ -0,0 +1,272 @@
////////////////////////////////////////////////////////////////////////////////
///
/// General FIR digital filter routines with MMX optimization.
///
/// Note : MMX optimized functions reside in a separate, platform-specific file,
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.16 $
//
// $Id: FIRFilter.cpp,v 1.16 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <memory.h>
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <stdexcept>
#include "FIRFilter.h"
#include "cpu_detect.h"
using namespace soundtouch;
/*****************************************************************************
*
* Implementation of the class 'FIRFilter'
*
*****************************************************************************/
FIRFilter::FIRFilter()
{
resultDivFactor = 0;
length = 0;
lengthDiv8 = 0;
filterCoeffs = NULL;
}
FIRFilter::~FIRFilter()
{
delete[] filterCoeffs;
}
// Usual C-version of the filter routine for stereo sound
uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
{
uint i, j, end;
LONG_SAMPLETYPE suml, sumr;
#ifdef FLOAT_SAMPLES
// when using floating point samples, use a scaler instead of a divider
// because division is much slower operation than multiplying.
double dScaler = 1.0 / (double)resultDivider;
#endif
assert(length != 0);
end = 2 * (numSamples - length);
for (j = 0; j < end; j += 2)
{
const SAMPLETYPE *ptr;
suml = sumr = 0;
ptr = src + j;
for (i = 0; i < length; i += 4)
{
// loop is unrolled by factor of 4 here for efficiency
suml += ptr[2 * i + 0] * filterCoeffs[i + 0] +
ptr[2 * i + 2] * filterCoeffs[i + 1] +
ptr[2 * i + 4] * filterCoeffs[i + 2] +
ptr[2 * i + 6] * filterCoeffs[i + 3];
sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] +
ptr[2 * i + 3] * filterCoeffs[i + 1] +
ptr[2 * i + 5] * filterCoeffs[i + 2] +
ptr[2 * i + 7] * filterCoeffs[i + 3];
}
#ifdef INTEGER_SAMPLES
suml >>= resultDivFactor;
sumr >>= resultDivFactor;
// saturate to 16 bit integer limits
suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml;
// saturate to 16 bit integer limits
sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr;
#else
suml *= dScaler;
sumr *= dScaler;
#endif // INTEGER_SAMPLES
dest[j] = (SAMPLETYPE)suml;
dest[j + 1] = (SAMPLETYPE)sumr;
}
return numSamples - length;
}
// Usual C-version of the filter routine for mono sound
uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
{
uint i, j, end;
LONG_SAMPLETYPE sum;
#ifdef FLOAT_SAMPLES
// when using floating point samples, use a scaler instead of a divider
// because division is much slower operation than multiplying.
double dScaler = 1.0 / (double)resultDivider;
#endif
assert(length != 0);
end = numSamples - length;
for (j = 0; j < end; j ++)
{
sum = 0;
for (i = 0; i < length; i += 4)
{
// loop is unrolled by factor of 4 here for efficiency
sum += src[i + 0] * filterCoeffs[i + 0] +
src[i + 1] * filterCoeffs[i + 1] +
src[i + 2] * filterCoeffs[i + 2] +
src[i + 3] * filterCoeffs[i + 3];
}
#ifdef INTEGER_SAMPLES
sum >>= resultDivFactor;
// saturate to 16 bit integer limits
sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum;
#else
sum *= dScaler;
#endif // INTEGER_SAMPLES
dest[j] = (SAMPLETYPE)sum;
src ++;
}
return end;
}
// Set filter coeffiecients and length.
//
// Throws an exception if filter length isn't divisible by 8
void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor)
{
assert(newLength > 0);
if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8");
lengthDiv8 = newLength / 8;
length = lengthDiv8 * 8;
assert(length == newLength);
resultDivFactor = uResultDivFactor;
#ifdef INTEGER_SAMPLES
resultDivider = (SAMPLETYPE)(1<<resultDivFactor);
#else
resultDivider = (SAMPLETYPE)powf(2, resultDivFactor);
#endif
delete[] filterCoeffs;
filterCoeffs = new SAMPLETYPE[length];
memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE));
}
uint FIRFilter::getLength() const
{
return length;
}
// Applies the filter to the given sequence of samples.
//
// Note : The amount of outputted samples is by value of 'filter_length'
// smaller than the amount of input samples.
uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
{
assert(numChannels == 1 || numChannels == 2);
assert(length > 0);
assert(lengthDiv8 * 8 == length);
if (numSamples < length) return 0;
assert(resultDivFactor >= 0);
if (numChannels == 2)
{
return evaluateFilterStereo(dest, src, numSamples);
} else {
return evaluateFilterMono(dest, src, numSamples);
}
}
// Operator 'new' is overloaded so that it automatically creates a suitable instance
// depending on if we've a MMX-capable CPU available or not.
void * FIRFilter::operator new(size_t s)
{
// Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead!
throw std::runtime_error("Don't use 'new FIRFilter', use 'newInstance' member instead!");
return NULL;
}
FIRFilter * FIRFilter::newInstance()
{
uint uExtensions = 0;
#if !defined(_MSC_VER) || !defined(__x86_64__)
uExtensions = detectCPUextensions();
#endif
// Check if MMX/SSE/3DNow! instruction set extensions supported by CPU
#ifdef ALLOW_MMX
// MMX routines available only with integer sample types
if (uExtensions & SUPPORT_MMX)
{
return ::new FIRFilterMMX;
}
else
#endif // ALLOW_MMX
#ifdef ALLOW_SSE
if (uExtensions & SUPPORT_SSE)
{
// SSE support
return ::new FIRFilterSSE;
}
else
#endif // ALLOW_SSE
#ifdef ALLOW_3DNOW
if (uExtensions & SUPPORT_3DNOW)
{
// 3DNow! support
return ::new FIRFilter3DNow;
}
else
#endif // ALLOW_3DNOW
{
// ISA optimizations not supported, use plain C version
return ::new FIRFilter;
}
}

View File

@ -0,0 +1,163 @@
////////////////////////////////////////////////////////////////////////////////
///
/// General FIR digital filter routines with MMX optimization.
///
/// Note : MMX optimized functions reside in a separate, platform-specific file,
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.17 $
//
// $Id: FIRFilter.h,v 1.17 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef FIRFilter_H
#define FIRFilter_H
#include "STTypes.h"
namespace soundtouch
{
class FIRFilter
{
protected:
// Number of FIR filter taps
uint length;
// Number of FIR filter taps divided by 8
uint lengthDiv8;
// Result divider factor in 2^k format
uint resultDivFactor;
// Result divider value.
SAMPLETYPE resultDivider;
// Memory for filter coefficients
SAMPLETYPE *filterCoeffs;
virtual uint evaluateFilterStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) const;
virtual uint evaluateFilterMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) const;
public:
FIRFilter();
virtual ~FIRFilter();
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we've a MMX-capable CPU available or not.
void * operator new(size_t s);
static FIRFilter *newInstance();
/// Applies the filter to the given sequence of samples.
/// Note : The amount of outputted samples is by value of 'filter_length'
/// smaller than the amount of input samples.
///
/// \return Number of samples copied to 'dest'.
uint evaluate(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples,
uint numChannels) const;
uint getLength() const;
virtual void setCoefficients(const SAMPLETYPE *coeffs,
uint newLength,
uint uResultDivFactor);
};
// Optional subclasses that implement CPU-specific optimizations:
#ifdef ALLOW_MMX
/// Class that implements MMX optimized functions exclusive for 16bit integer samples type.
class FIRFilterMMX : public FIRFilter
{
protected:
short *filterCoeffsUnalign;
short *filterCoeffsAlign;
virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const;
public:
FIRFilterMMX();
~FIRFilterMMX();
virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor);
};
#endif // ALLOW_MMX
#ifdef ALLOW_3DNOW
/// Class that implements 3DNow! optimized functions exclusive for floating point samples type.
class FIRFilter3DNow : public FIRFilter
{
protected:
float *filterCoeffsUnalign;
float *filterCoeffsAlign;
virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const;
public:
FIRFilter3DNow();
~FIRFilter3DNow();
virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor);
};
#endif // ALLOW_3DNOW
#ifdef ALLOW_SSE
/// Class that implements SSE optimized functions exclusive for floating point samples type.
class FIRFilterSSE : public FIRFilter
{
protected:
float *filterCoeffsUnalign;
float *filterCoeffsAlign;
virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const;
public:
FIRFilterSSE();
~FIRFilterSSE();
virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor);
};
#endif // ALLOW_SSE
}
#endif // FIRFilter_H

View File

@ -0,0 +1,45 @@
## Process this file with automake to create Makefile.in
##
## $Id: Makefile.am,v 1.3 2006/02/05 18:33:34 Olli Exp $
##
## Copyright (C) 2003 - David W. Durham
##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
##
## SoundTouch 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.
##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA
AUTOMAKE_OPTIONS = foreign
noinst_HEADERS=AAFilter.h cpu_detect.h cpu_detect_x86_gcc.cpp FIRFilter.h RateTransposer.h TDStretch.h
noinst_LIBRARIES = libSoundTouch.a
if X86_64
libSoundTouch_a_CXXFLAGS = -fPIC
libSoundTouch_a_CFLAGS = -fPIC
else
libSoundTouch_a_CXXFLAGS = -msse -mmmx
libSoundTouch_a_CFLAGS = -msse -mmmx
endif
#lib_LTLIBRARIES=libSoundTouch.la
# the mmx_gcc.cpp and cpu_detect_x86_gcc.cpp may need to be conditionally included here from things discovered in configure.ac
libSoundTouch_a_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp mmx_optimized.cpp sse_optimized.cpp RateTransposer.cpp SoundTouch.cpp TDStretch.cpp cpu_detect_x86_gcc.cpp WavFile.cpp
# ??? test for -fcheck-new in configure.ac
# other compiler flags to add
AM_CXXFLAGS=-O3 -msse -fcheck-new -I../../include
# other linking flags to add
#libSoundTouch_la_LIBADD=

View File

@ -0,0 +1,626 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Sample rate transposer. Changes sample rate by using linear interpolation
/// together with anti-alias filtering (first order interpolation with anti-
/// alias filtering should be quite adequate for this application)
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/03/19 10:05:49 $
// File revision : $Revision: 1.13 $
//
// $Id: RateTransposer.cpp,v 1.13 2006/03/19 10:05:49 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <memory.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include "RateTransposer.h"
#include "AAFilter.h"
using namespace soundtouch;
/// A linear samplerate transposer class that uses integer arithmetics.
/// for the transposing.
class RateTransposerInteger : public RateTransposer
{
protected:
int iSlopeCount;
uint uRate;
SAMPLETYPE sPrevSampleL, sPrevSampleR;
virtual void resetRegisters();
virtual uint transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples);
virtual uint transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples);
public:
RateTransposerInteger();
virtual ~RateTransposerInteger();
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower
/// rate, larger faster rates.
virtual void setRate(float newRate);
};
/// A linear samplerate transposer class that uses floating point arithmetics
/// for the transposing.
class RateTransposerFloat : public RateTransposer
{
protected:
float fSlopeCount;
float fRateStep;
SAMPLETYPE sPrevSampleL, sPrevSampleR;
virtual void resetRegisters();
virtual uint transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples);
virtual uint transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples);
public:
RateTransposerFloat();
virtual ~RateTransposerFloat();
};
#ifndef min
#define min(a,b) ((a > b) ? b : a)
#define max(a,b) ((a < b) ? b : a)
#endif
// Operator 'new' is overloaded so that it automatically creates a suitable instance
// depending on if we've a MMX/SSE/etc-capable CPU available or not.
void * RateTransposer::operator new(size_t s)
{
// Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead!
assert(FALSE);
return NULL;
}
RateTransposer *RateTransposer::newInstance()
{
#ifdef INTEGER_SAMPLES
return ::new RateTransposerInteger;
#else
return ::new RateTransposerFloat;
#endif
}
// Constructor
RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
{
uChannels = 2;
bUseAAFilter = TRUE;
// Instantiates the anti-alias filter with default tap length
// of 32
pAAFilter = new AAFilter(32);
}
RateTransposer::~RateTransposer()
{
delete pAAFilter;
}
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
void RateTransposer::enableAAFilter(const BOOL newMode)
{
bUseAAFilter = newMode;
}
/// Returns nonzero if anti-alias filter is enabled.
BOOL RateTransposer::isAAFilterEnabled() const
{
return bUseAAFilter;
}
AAFilter *RateTransposer::getAAFilter() const
{
return pAAFilter;
}
// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower
// uRate, larger faster uRates.
void RateTransposer::setRate(float newRate)
{
float fCutoff;
fRate = newRate;
// design a new anti-alias filter
if (newRate > 1.0f)
{
fCutoff = 0.5f / newRate;
}
else
{
fCutoff = 0.5f * newRate;
}
pAAFilter->setCutoffFreq(fCutoff);
}
// Outputs as many samples of the 'outputBuffer' as possible, and if there's
// any room left, outputs also as many of the incoming samples as possible.
// The goal is to drive the outputBuffer empty.
//
// It's allowed for 'output' and 'input' parameters to point to the same
// memory position.
void RateTransposer::flushStoreBuffer()
{
if (storeBuffer.isEmpty()) return;
outputBuffer.moveSamples(storeBuffer);
}
// Adds 'numSamples' pcs of samples from the 'samples' memory position into
// the input of the object.
void RateTransposer::putSamples(const SAMPLETYPE *samples, uint numSamples)
{
processSamples(samples, numSamples);
}
// Transposes up the sample rate, causing the observed playback 'rate' of the
// sound to decrease
void RateTransposer::upsample(const SAMPLETYPE *src, uint numSamples)
{
int count, sizeTemp, num;
// If the parameter 'uRate' value is smaller than 'SCALE', first transpose
// the samples and then apply the anti-alias filter to remove aliasing.
// First check that there's enough room in 'storeBuffer'
// (+16 is to reserve some slack in the destination buffer)
sizeTemp = (int)((float)numSamples / fRate + 16.0f);
// Transpose the samples, store the result into the end of "storeBuffer"
count = transpose(storeBuffer.ptrEnd(sizeTemp), src, numSamples);
storeBuffer.putSamples(count);
// Apply the anti-alias filter to samples in "store output", output the
// result to "dest"
num = storeBuffer.numSamples();
count = pAAFilter->evaluate(outputBuffer.ptrEnd(num),
storeBuffer.ptrBegin(), num, uChannels);
outputBuffer.putSamples(count);
// Remove the processed samples from "storeBuffer"
storeBuffer.receiveSamples(count);
}
// Transposes down the sample rate, causing the observed playback 'rate' of the
// sound to increase
void RateTransposer::downsample(const SAMPLETYPE *src, uint numSamples)
{
int count, sizeTemp;
// If the parameter 'uRate' value is larger than 'SCALE', first apply the
// anti-alias filter to remove high frequencies (prevent them from folding
// over the lover frequencies), then transpose. */
// Add the new samples to the end of the storeBuffer */
storeBuffer.putSamples(src, numSamples);
// Anti-alias filter the samples to prevent folding and output the filtered
// data to tempBuffer. Note : because of the FIR filter length, the
// filtering routine takes in 'filter_length' more samples than it outputs.
assert(tempBuffer.isEmpty());
sizeTemp = storeBuffer.numSamples();
count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp),
storeBuffer.ptrBegin(), sizeTemp, uChannels);
// Remove the filtered samples from 'storeBuffer'
storeBuffer.receiveSamples(count);
// Transpose the samples (+16 is to reserve some slack in the destination buffer)
sizeTemp = (int)((float)numSamples / fRate + 16.0f);
count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count);
outputBuffer.putSamples(count);
}
// Transposes sample rate by applying anti-alias filter to prevent folding.
// Returns amount of samples returned in the "dest" buffer.
// The maximum amount of samples that can be returned at a time is set by
// the 'set_returnBuffer_size' function.
void RateTransposer::processSamples(const SAMPLETYPE *src, uint numSamples)
{
uint count;
uint sizeReq;
if (numSamples == 0) return;
assert(pAAFilter);
// If anti-alias filter is turned off, simply transpose without applying
// the filter
if (bUseAAFilter == FALSE)
{
sizeReq = (int)((float)numSamples / fRate + 1.0f);
count = transpose(outputBuffer.ptrEnd(sizeReq), src, numSamples);
outputBuffer.putSamples(count);
return;
}
// Transpose with anti-alias filter
if (fRate < 1.0f)
{
upsample(src, numSamples);
}
else
{
downsample(src, numSamples);
}
}
// Transposes the sample rate of the given samples using linear interpolation.
// Returns the number of samples returned in the "dest" buffer
inline uint RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples)
{
if (uChannels == 2)
{
return transposeStereo(dest, src, numSamples);
}
else
{
return transposeMono(dest, src, numSamples);
}
}
// Sets the number of channels, 1 = mono, 2 = stereo
void RateTransposer::setChannels(const uint numchannels)
{
if (uChannels == numchannels) return;
assert(numchannels == 1 || numchannels == 2);
uChannels = numchannels;
storeBuffer.setChannels(uChannels);
tempBuffer.setChannels(uChannels);
outputBuffer.setChannels(uChannels);
// Inits the linear interpolation registers
resetRegisters();
}
// Clears all the samples in the object
void RateTransposer::clear()
{
outputBuffer.clear();
storeBuffer.clear();
}
// Returns nonzero if there aren't any samples available for outputting.
uint RateTransposer::isEmpty()
{
int res;
res = FIFOProcessor::isEmpty();
if (res == 0) return 0;
return storeBuffer.isEmpty();
}
//////////////////////////////////////////////////////////////////////////////
//
// RateTransposerInteger - integer arithmetic implementation
//
/// fixed-point interpolation routine precision
#define SCALE 65536
// Constructor
RateTransposerInteger::RateTransposerInteger() : RateTransposer()
{
// call these here as these are virtual functions; calling these
// from the base class constructor wouldn't execute the overloaded
// versions (<master yoda>peculiar C++ can be</my>).
resetRegisters();
setRate(1.0f);
}
RateTransposerInteger::~RateTransposerInteger()
{
}
void RateTransposerInteger::resetRegisters()
{
iSlopeCount = 0;
sPrevSampleL =
sPrevSampleR = 0;
}
// Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer
uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples)
{
unsigned int i, used;
LONG_SAMPLETYPE temp, vol1;
used = 0;
i = 0;
// Process the last sample saved from the previous call first...
while (iSlopeCount <= SCALE)
{
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
temp = vol1 * sPrevSampleL + iSlopeCount * src[0];
dest[i] = (SAMPLETYPE)(temp / SCALE);
i++;
iSlopeCount += uRate;
}
// now always (iSlopeCount > SCALE)
iSlopeCount -= SCALE;
while (1)
{
while (iSlopeCount > SCALE)
{
iSlopeCount -= SCALE;
used ++;
if (used >= numSamples - 1) goto end;
}
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
temp = src[used] * vol1 + iSlopeCount * src[used + 1];
dest[i] = (SAMPLETYPE)(temp / SCALE);
i++;
iSlopeCount += uRate;
}
end:
// Store the last sample for the next round
sPrevSampleL = src[numSamples - 1];
return i;
}
// Transposes the sample rate of the given samples using linear interpolation.
// 'Stereo' version of the routine. Returns the number of samples returned in
// the "dest" buffer
uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples)
{
unsigned int srcPos, i, used;
LONG_SAMPLETYPE temp, vol1;
if (numSamples == 0) return 0; // no samples, no work
used = 0;
i = 0;
// Process the last sample saved from the sPrevSampleLious call first...
while (iSlopeCount <= SCALE)
{
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
temp = vol1 * sPrevSampleL + iSlopeCount * src[0];
dest[2 * i] = (SAMPLETYPE)(temp / SCALE);
temp = vol1 * sPrevSampleR + iSlopeCount * src[1];
dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE);
i++;
iSlopeCount += uRate;
}
// now always (iSlopeCount > SCALE)
iSlopeCount -= SCALE;
while (1)
{
while (iSlopeCount > SCALE)
{
iSlopeCount -= SCALE;
used ++;
if (used >= numSamples - 1) goto end;
}
srcPos = 2 * used;
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
temp = src[srcPos] * vol1 + iSlopeCount * src[srcPos + 2];
dest[2 * i] = (SAMPLETYPE)(temp / SCALE);
temp = src[srcPos + 1] * vol1 + iSlopeCount * src[srcPos + 3];
dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE);
i++;
iSlopeCount += uRate;
}
end:
// Store the last sample for the next round
sPrevSampleL = src[2 * numSamples - 2];
sPrevSampleR = src[2 * numSamples - 1];
return i;
}
// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower
// uRate, larger faster uRates.
void RateTransposerInteger::setRate(float newRate)
{
uRate = (int)(newRate * SCALE + 0.5f);
RateTransposer::setRate(newRate);
}
//////////////////////////////////////////////////////////////////////////////
//
// RateTransposerFloat - floating point arithmetic implementation
//
//////////////////////////////////////////////////////////////////////////////
// Constructor
RateTransposerFloat::RateTransposerFloat() : RateTransposer()
{
// call these here as these are virtual functions; calling these
// from the base class constructor wouldn't execute the overloaded
// versions (<master yoda>peculiar C++ can be</my>).
resetRegisters();
setRate(1.0f);
}
RateTransposerFloat::~RateTransposerFloat()
{
}
void RateTransposerFloat::resetRegisters()
{
fSlopeCount = 0;
sPrevSampleL =
sPrevSampleR = 0;
}
// Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer
uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples)
{
unsigned int i, used;
used = 0;
i = 0;
// Process the last sample saved from the previous call first...
while (fSlopeCount <= 1.0f)
{
dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]);
i++;
fSlopeCount += fRate;
}
fSlopeCount -= 1.0f;
if (numSamples == 1) goto end;
while (1)
{
while (fSlopeCount > 1.0f)
{
fSlopeCount -= 1.0f;
used ++;
if (used >= numSamples - 1) goto end;
}
dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[used] + fSlopeCount * src[used + 1]);
i++;
fSlopeCount += fRate;
}
end:
// Store the last sample for the next round
sPrevSampleL = src[numSamples - 1];
return i;
}
// Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer
uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples)
{
unsigned int srcPos, i, used;
if (numSamples == 0) return 0; // no samples, no work
used = 0;
i = 0;
// Process the last sample saved from the sPrevSampleLious call first...
while (fSlopeCount <= 1.0f)
{
dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]);
dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]);
i++;
fSlopeCount += fRate;
}
// now always (iSlopeCount > 1.0f)
fSlopeCount -= 1.0f;
if (numSamples == 1) goto end;
while (1)
{
while (fSlopeCount > 1.0f)
{
fSlopeCount -= 1.0f;
used ++;
if (used >= numSamples - 1) goto end;
}
srcPos = 2 * used;
dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos]
+ fSlopeCount * src[srcPos + 2]);
dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1]
+ fSlopeCount * src[srcPos + 3]);
i++;
fSlopeCount += fRate;
}
end:
// Store the last sample for the next round
sPrevSampleL = src[2 * numSamples - 2];
sPrevSampleR = src[2 * numSamples - 1];
return i;
}

View File

@ -0,0 +1,162 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Sample rate transposer. Changes sample rate by using linear interpolation
/// together with anti-alias filtering (first order interpolation with anti-
/// alias filtering should be quite adequate for this application).
///
/// Use either of the derived classes of 'RateTransposerInteger' or
/// 'RateTransposerFloat' for corresponding integer/floating point tranposing
/// algorithm implementation.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.10 $
//
// $Id: RateTransposer.h,v 1.10 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef RateTransposer_H
#define RateTransposer_H
#include "AAFilter.h"
#include "FIFOSamplePipe.h"
#include "FIFOSampleBuffer.h"
#include "STTypes.h"
namespace soundtouch
{
/// A common linear samplerate transposer class.
///
/// Note: Use function "RateTransposer::newInstance()" to create a new class
/// instance instead of the "new" operator; that function automatically
/// chooses a correct implementation depending on if integer or floating
/// arithmetics are to be used.
class RateTransposer : public FIFOProcessor
{
protected:
/// Anti-alias filter object
AAFilter *pAAFilter;
float fRate;
uint uChannels;
/// Buffer for collecting samples to feed the anti-alias filter between
/// two batches
FIFOSampleBuffer storeBuffer;
/// Buffer for keeping samples between transposing & anti-alias filter
FIFOSampleBuffer tempBuffer;
/// Output sample buffer
FIFOSampleBuffer outputBuffer;
BOOL bUseAAFilter;
void init();
virtual void resetRegisters() = 0;
virtual uint transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) = 0;
virtual uint transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) = 0;
uint transpose(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples);
void flushStoreBuffer();
void downsample(const SAMPLETYPE *src,
uint numSamples);
void upsample(const SAMPLETYPE *src,
uint numSamples);
/// Transposes sample rate by applying anti-alias filter to prevent folding.
/// Returns amount of samples returned in the "dest" buffer.
/// The maximum amount of samples that can be returned at a time is set by
/// the 'set_returnBuffer_size' function.
void processSamples(const SAMPLETYPE *src,
uint numSamples);
public:
RateTransposer();
virtual ~RateTransposer();
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we're to use integer or floating point arithmetics.
void *operator new(size_t s);
/// Use this function instead of "new" operator to create a new instance of this class.
/// This function automatically chooses a correct implementation, depending on if
/// integer ot floating point arithmetics are to be used.
static RateTransposer *newInstance();
/// Returns the output buffer object
FIFOSamplePipe *getOutput() { return &outputBuffer; };
/// Returns the store buffer object
FIFOSamplePipe *getStore() { return &storeBuffer; };
/// Return anti-alias filter object
AAFilter *getAAFilter() const;
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
void enableAAFilter(BOOL newMode);
/// Returns nonzero if anti-alias filter is enabled.
BOOL isAAFilterEnabled() const;
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower
/// rate, larger faster rates.
virtual void setRate(float newRate);
/// Sets the number of channels, 1 = mono, 2 = stereo
void setChannels(uint channels);
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into
/// the input of the object.
void putSamples(const SAMPLETYPE *samples, uint numSamples);
/// Clears all the samples in the object
void clear();
/// Returns nonzero if there aren't any samples available for outputting.
uint isEmpty();
};
}
#endif

View File

@ -0,0 +1,197 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Common type definitions for SoundTouch audio processing library.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.16 $
//
// $Id: STTypes.h,v 1.16 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef STTypes_H
#define STTypes_H
//#define INTEGER_SAMPLES 1
typedef unsigned int uint;
typedef unsigned long ulong;
#ifdef __x86_64__
typedef unsigned long long ulongptr;
#else
typedef unsigned long ulongptr;
#endif
#ifdef __GNUC__
// In GCC, include soundtouch_config.h made by config scritps
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `m' library (-lm). */
#define HAVE_LIBM 1
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#define HAVE_MALLOC 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Use Integer as Sample type */
#define INTEGER_SAMPLES 1
/* Define as the return type of signal handlers (`int' or `void'). */
#define RETSIGTYPE void
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
#endif
#ifndef _WINDEF_
// if these aren't defined already by Windows headers, define now
typedef int BOOL;
#define FALSE 0
#define TRUE 1
#endif // _WINDEF_
namespace soundtouch
{
/// Activate these undef's to overrule the possible sampletype
/// setting inherited from some other header file:
//#undef INTEGER_SAMPLES
//#undef FLOAT_SAMPLES
#if !(INTEGER_SAMPLES || FLOAT_SAMPLES)
/// Choose either 32bit floating point or 16bit integer sampletype
/// by choosing one of the following defines, unless this selection
/// has already been done in some other file.
////
/// Notes:
/// - In Windows environment, choose the sample format with the
/// following defines.
/// - In GNU environment, the floating point samples are used by
/// default, but integer samples can be chosen by giving the
/// following switch to the configure script:
/// ./configure --enable-integer-samples
/// However, if you still prefer to select the sample format here
/// also in GNU environment, then please #undef the INTEGER_SAMPLE
/// and FLOAT_SAMPLE defines first as in comments above.
//#define INTEGER_SAMPLES 1 //< 16bit integer samples
#define FLOAT_SAMPLES 1 //< 32bit float samples
#endif
/// Define this to allow CPU-specific assembler optimizations. Notice that
/// having this enabled on non-x86 platforms doesn't matter; the compiler can
/// drop unsupported extensions on different platforms automatically.
/// However, if you're having difficulties getting the optimized routines
/// compiled with your compler (e.g. some gcc compiler versions may be picky),
/// you may wish to disable the optimizations to make the library compile.
#if !defined(_MSC_VER) || !defined(__x86_64__)
#define ALLOW_OPTIMIZATIONS 1
#define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1
#endif
// If defined, allows the SIMD-optimized routines to take minor shortcuts
// for improved performance. Undefine to require faithfully similar SIMD
// calculations as in normal C implementation.
#ifdef INTEGER_SAMPLES
// 16bit integer sample type
typedef short SAMPLETYPE;
// data type for sample accumulation: Use 32bit integer to prevent overflows
typedef long LONG_SAMPLETYPE;
#ifdef FLOAT_SAMPLES
// check that only one sample type is defined
#error "conflicting sample types defined"
#endif // FLOAT_SAMPLES
#ifdef ALLOW_OPTIMIZATIONS
#if (_WIN32 || __i386__ || __x86_64__)
// Allow MMX optimizations
#define ALLOW_MMX 1
#endif
#endif
#else
// floating point samples
typedef float SAMPLETYPE;
// data type for sample accumulation: Use double to utilize full precision.
typedef double LONG_SAMPLETYPE;
#ifdef ALLOW_OPTIMIZATIONS
// Allow 3DNow! and SSE optimizations
#if _WIN32
// #define ALLOW_3DNOW 1
#endif
#if (_WIN32 || __i386__ || __x86_64__)
#define ALLOW_SSE 1
#endif
#endif
#endif // INTEGER_SAMPLES
};
#endif

View File

@ -0,0 +1,474 @@
//////////////////////////////////////////////////////////////////////////////
///
/// SoundTouch - main class for tempo/pitch/rate adjusting routines.
///
/// Notes:
/// - Initialize the SoundTouch object instance by setting up the sound stream
/// parameters with functions 'setSampleRate' and 'setChannels', then set
/// desired tempo/pitch/rate settings with the corresponding functions.
///
/// - The SoundTouch class behaves like a first-in-first-out pipeline: The
/// samples that are to be processed are fed into one of the pipe by calling
/// function 'putSamples', while the ready processed samples can be read
/// from the other end of the pipeline with function 'receiveSamples'.
///
/// - The SoundTouch processing classes require certain sized 'batches' of
/// samples in order to process the sound. For this reason the classes buffer
/// incoming samples until there are enough of samples available for
/// processing, then they carry out the processing step and consequently
/// make the processed samples available for outputting.
///
/// - For the above reason, the processing routines introduce a certain
/// 'latency' between the input and output, so that the samples input to
/// SoundTouch may not be immediately available in the output, and neither
/// the amount of outputtable samples may not immediately be in direct
/// relationship with the amount of previously input samples.
///
/// - The tempo/pitch/rate control parameters can be altered during processing.
/// Please notice though that they aren't currently protected by semaphores,
/// so in multi-thread application external semaphore protection may be
/// required.
///
/// - This class utilizes classes 'TDStretch' for tempo change (without modifying
/// pitch) and 'RateTransposer' for changing the playback rate (that is, both
/// tempo and pitch in the same ratio) of the sound. The third available control
/// 'pitch' (change pitch but maintain tempo) is produced by a combination of
/// combining the two other controls.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.13 $
//
// $Id: SoundTouch.cpp,v 1.13 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <assert.h>
#include <stdlib.h>
#include <memory.h>
#include <math.h>
#include <stdexcept>
#include <stdio.h>
#include "SoundTouch.h"
#include "TDStretch.h"
#include "RateTransposer.h"
#include "cpu_detect.h"
using namespace soundtouch;
/// Print library version string
extern "C" void soundtouch_ac_test()
{
printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION);
}
SoundTouch::SoundTouch()
{
// Initialize rate transposer and tempo changer instances
pRateTransposer = RateTransposer::newInstance();
pTDStretch = TDStretch::newInstance();
setOutPipe(pTDStretch);
rate = tempo = 0;
virtualPitch =
virtualRate =
virtualTempo = 1.0;
calcEffectiveRateAndTempo();
channels = 0;
bSrateSet = FALSE;
}
SoundTouch::~SoundTouch()
{
delete pRateTransposer;
delete pTDStretch;
}
/// Get SoundTouch library version string
const char *SoundTouch::getVersionString()
{
static const char *_version = SOUNDTOUCH_VERSION;
return _version;
}
/// Get SoundTouch library version Id
uint SoundTouch::getVersionId()
{
return SOUNDTOUCH_VERSION_ID;
}
// Sets the number of channels, 1 = mono, 2 = stereo
void SoundTouch::setChannels(uint numChannels)
{
if (numChannels != 1 && numChannels != 2)
{
throw std::runtime_error("Illegal number of channels");
}
channels = numChannels;
pRateTransposer->setChannels(numChannels);
pTDStretch->setChannels(numChannels);
}
// Sets new rate control value. Normal rate = 1.0, smaller values
// represent slower rate, larger faster rates.
void SoundTouch::setRate(float newRate)
{
virtualRate = newRate;
calcEffectiveRateAndTempo();
}
// Sets new rate control value as a difference in percents compared
// to the original rate (-50 .. +100 %)
void SoundTouch::setRateChange(float newRate)
{
virtualRate = 1.0f + 0.01f * newRate;
calcEffectiveRateAndTempo();
}
// Sets new tempo control value. Normal tempo = 1.0, smaller values
// represent slower tempo, larger faster tempo.
void SoundTouch::setTempo(float newTempo)
{
virtualTempo = newTempo;
calcEffectiveRateAndTempo();
}
// Sets new tempo control value as a difference in percents compared
// to the original tempo (-50 .. +100 %)
void SoundTouch::setTempoChange(float newTempo)
{
virtualTempo = 1.0f + 0.01f * newTempo;
calcEffectiveRateAndTempo();
}
// Sets new pitch control value. Original pitch = 1.0, smaller values
// represent lower pitches, larger values higher pitch.
void SoundTouch::setPitch(float newPitch)
{
virtualPitch = newPitch;
calcEffectiveRateAndTempo();
}
// Sets pitch change in octaves compared to the original pitch
// (-1.00 .. +1.00)
void SoundTouch::setPitchOctaves(float newPitch)
{
virtualPitch = (float)exp(0.69314718056f * newPitch);
calcEffectiveRateAndTempo();
}
// Sets pitch change in semi-tones compared to the original pitch
// (-12 .. +12)
void SoundTouch::setPitchSemiTones(int newPitch)
{
setPitchOctaves((float)newPitch / 12.0f);
}
void SoundTouch::setPitchSemiTones(float newPitch)
{
setPitchOctaves(newPitch / 12.0f);
}
// Calculates 'effective' rate and tempo values from the
// nominal control values.
void SoundTouch::calcEffectiveRateAndTempo()
{
float oldTempo = tempo;
float oldRate = rate;
tempo = virtualTempo / virtualPitch;
rate = virtualPitch * virtualRate;
if (rate != oldRate) pRateTransposer->setRate(rate);
if (tempo != oldTempo) pTDStretch->setTempo(tempo);
if (rate > 1.0f)
{
if (output != pRateTransposer)
{
FIFOSamplePipe *transOut;
assert(output == pTDStretch);
// move samples in the current output buffer to the output of pRateTransposer
transOut = pRateTransposer->getOutput();
transOut->moveSamples(*output);
// move samples in tempo changer's input to pitch transposer's input
pRateTransposer->moveSamples(*pTDStretch->getInput());
output = pRateTransposer;
}
}
else
{
if (output != pTDStretch)
{
FIFOSamplePipe *tempoOut;
assert(output == pRateTransposer);
// move samples in the current output buffer to the output of pTDStretch
tempoOut = pTDStretch->getOutput();
tempoOut->moveSamples(*output);
// move samples in pitch transposer's store buffer to tempo changer's input
pTDStretch->moveSamples(*pRateTransposer->getStore());
output = pTDStretch;
}
}
}
// Sets sample rate.
void SoundTouch::setSampleRate(uint srate)
{
bSrateSet = TRUE;
// set sample rate, leave other tempo changer parameters as they are.
pTDStretch->setParameters(srate);
}
// Adds 'numSamples' pcs of samples from the 'samples' memory position into
// the input of the object.
void SoundTouch::putSamples(const SAMPLETYPE *samples, uint numSamples)
{
if (bSrateSet == FALSE)
{
throw std::runtime_error("SoundTouch : Sample rate not defined");
}
else if (channels == 0)
{
throw std::runtime_error("SoundTouch : Number of channels not defined");
}
// Transpose the rate of the new samples if necessary
/* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value...
if (rate == 1.0f)
{
// The rate value is same as the original, simply evaluate the tempo changer.
assert(output == pTDStretch);
if (pRateTransposer->isEmpty() == 0)
{
// yet flush the last samples in the pitch transposer buffer
// (may happen if 'rate' changes from a non-zero value to zero)
pTDStretch->moveSamples(*pRateTransposer);
}
pTDStretch->putSamples(samples, numSamples);
}
*/
else if (rate <= 1.0f)
{
// transpose the rate down, output the transposed sound to tempo changer buffer
assert(output == pTDStretch);
pRateTransposer->putSamples(samples, numSamples);
pTDStretch->moveSamples(*pRateTransposer);
}
else
{
assert(rate > 1.0f);
// evaluate the tempo changer, then transpose the rate up,
assert(output == pRateTransposer);
pTDStretch->putSamples(samples, numSamples);
pRateTransposer->moveSamples(*pTDStretch);
}
}
// Flushes the last samples from the processing pipeline to the output.
// Clears also the internal processing buffers.
//
// Note: This function is meant for extracting the last samples of a sound
// stream. This function may introduce additional blank samples in the end
// of the sound stream, and thus it's not recommended to call this function
// in the middle of a sound stream.
void SoundTouch::flush()
{
int i;
uint nOut;
SAMPLETYPE buff[128];
nOut = numSamples();
memset(buff, 0, 128 * sizeof(SAMPLETYPE));
// "Push" the last active samples out from the processing pipeline by
// feeding blank samples into the processing pipeline until new,
// processed samples appear in the output (not however, more than
// 8ksamples in any case)
for (i = 0; i < 128; i ++)
{
putSamples(buff, 64);
if (numSamples() != nOut) break; // new samples have appeared in the output!
}
// Clear working buffers
pRateTransposer->clear();
pTDStretch->clearInput();
// yet leave the 'tempoChanger' output intouched as that's where the
// flushed samples are!
}
// Changes a setting controlling the processing system behaviour. See the
// 'SETTING_...' defines for available setting ID's.
BOOL SoundTouch::setSetting(uint settingId, uint value)
{
uint sampleRate, sequenceMs, seekWindowMs, overlapMs;
// read current tdstretch routine parameters
pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs);
switch (settingId)
{
case SETTING_USE_AA_FILTER :
// enables / disabless anti-alias filter
pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE);
return TRUE;
case SETTING_AA_FILTER_LENGTH :
// sets anti-alias filter length
pRateTransposer->getAAFilter()->setLength(value);
return TRUE;
case SETTING_USE_QUICKSEEK :
// enables / disables tempo routine quick seeking algorithm
pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE);
return TRUE;
case SETTING_SEQUENCE_MS:
// change time-stretch sequence duration parameter
pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs);
return TRUE;
case SETTING_SEEKWINDOW_MS:
// change time-stretch seek window length parameter
pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs);
return TRUE;
case SETTING_OVERLAP_MS:
// change time-stretch overlap length parameter
pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value);
return TRUE;
default :
return FALSE;
}
}
// Reads a setting controlling the processing system behaviour. See the
// 'SETTING_...' defines for available setting ID's.
//
// Returns the setting value.
uint SoundTouch::getSetting(uint settingId) const
{
uint temp;
switch (settingId)
{
case SETTING_USE_AA_FILTER :
return pRateTransposer->isAAFilterEnabled();
case SETTING_AA_FILTER_LENGTH :
return pRateTransposer->getAAFilter()->getLength();
case SETTING_USE_QUICKSEEK :
return pTDStretch->isQuickSeekEnabled();
case SETTING_SEQUENCE_MS:
pTDStretch->getParameters(NULL, &temp, NULL, NULL);
return temp;
case SETTING_SEEKWINDOW_MS:
pTDStretch->getParameters(NULL, NULL, &temp, NULL);
return temp;
case SETTING_OVERLAP_MS:
pTDStretch->getParameters(NULL, NULL, NULL, &temp);
return temp;
default :
return 0;
}
}
// Clears all the samples in the object's output and internal processing
// buffers.
void SoundTouch::clear()
{
pRateTransposer->clear();
pTDStretch->clear();
}
/// Returns number of samples currently unprocessed.
uint SoundTouch::numUnprocessedSamples() const
{
FIFOSamplePipe * psp;
if (pTDStretch)
{
psp = pTDStretch->getInput();
if (psp)
{
return psp->numSamples();
}
}
return 0;
}

View File

@ -0,0 +1,252 @@
//////////////////////////////////////////////////////////////////////////////
///
/// SoundTouch - main class for tempo/pitch/rate adjusting routines.
///
/// Notes:
/// - Initialize the SoundTouch object instance by setting up the sound stream
/// parameters with functions 'setSampleRate' and 'setChannels', then set
/// desired tempo/pitch/rate settings with the corresponding functions.
///
/// - The SoundTouch class behaves like a first-in-first-out pipeline: The
/// samples that are to be processed are fed into one of the pipe by calling
/// function 'putSamples', while the ready processed samples can be read
/// from the other end of the pipeline with function 'receiveSamples'.
///
/// - The SoundTouch processing classes require certain sized 'batches' of
/// samples in order to process the sound. For this reason the classes buffer
/// incoming samples until there are enough of samples available for
/// processing, then they carry out the processing step and consequently
/// make the processed samples available for outputting.
///
/// - For the above reason, the processing routines introduce a certain
/// 'latency' between the input and output, so that the samples input to
/// SoundTouch may not be immediately available in the output, and neither
/// the amount of outputtable samples may not immediately be in direct
/// relationship with the amount of previously input samples.
///
/// - The tempo/pitch/rate control parameters can be altered during processing.
/// Please notice though that they aren't currently protected by semaphores,
/// so in multi-thread application external semaphore protection may be
/// required.
///
/// - This class utilizes classes 'TDStretch' for tempo change (without modifying
/// pitch) and 'RateTransposer' for changing the playback rate (that is, both
/// tempo and pitch in the same ratio) of the sound. The third available control
/// 'pitch' (change pitch but maintain tempo) is produced by a combination of
/// combining the two other controls.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.14 $
//
// $Id: SoundTouch.h,v 1.14 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef SoundTouch_H
#define SoundTouch_H
#include "FIFOSamplePipe.h"
#include "STTypes.h"
namespace soundtouch
{
/// Soundtouch library version string
#define SOUNDTOUCH_VERSION "1.3.1"
/// SoundTouch library version id
#define SOUNDTOUCH_VERSION_ID 010301
//
// Available setting IDs for the 'setSetting' & 'get_setting' functions:
/// Enable/disable anti-alias filter in pitch transposer (0 = disable)
#define SETTING_USE_AA_FILTER 0
/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32)
#define SETTING_AA_FILTER_LENGTH 1
/// Enable/disable quick seeking algorithm in tempo changer routine
/// (enabling quick seeking lowers CPU utilization but causes a minor sound
/// quality compromising)
#define SETTING_USE_QUICKSEEK 2
/// Time-stretch algorithm single processing sequence length in milliseconds. This determines
/// to how long sequences the original sound is chopped in the time-stretch algorithm.
/// See "STTypes.h" or README for more information.
#define SETTING_SEQUENCE_MS 3
/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the
/// best possible overlapping location. This determines from how wide window the algorithm
/// may look for an optimal joining location when mixing the sound sequences back together.
/// See "STTypes.h" or README for more information.
#define SETTING_SEEKWINDOW_MS 4
/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences
/// are mixed back together, to form a continuous sound stream, this parameter defines over
/// how long period the two consecutive sequences are let to overlap each other.
/// See "STTypes.h" or README for more information.
#define SETTING_OVERLAP_MS 5
class SoundTouch : public FIFOProcessor
{
private:
/// Rate transposer class instance
class RateTransposer *pRateTransposer;
/// Time-stretch class instance
class TDStretch *pTDStretch;
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
float virtualRate;
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
float virtualTempo;
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
float virtualPitch;
/// Flag: Has sample rate been set?
BOOL bSrateSet;
/// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and
/// 'virtualPitch' parameters.
void calcEffectiveRateAndTempo();
protected :
/// Number of channels
uint channels;
/// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
float rate;
/// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
float tempo;
public:
SoundTouch();
virtual ~SoundTouch();
/// Get SoundTouch library version string
static const char *getVersionString();
/// Get SoundTouch library version Id
static uint getVersionId();
/// Sets new rate control value. Normal rate = 1.0, smaller values
/// represent slower rate, larger faster rates.
void setRate(float newRate);
/// Sets new tempo control value. Normal tempo = 1.0, smaller values
/// represent slower tempo, larger faster tempo.
void setTempo(float newTempo);
/// Sets new rate control value as a difference in percents compared
/// to the original rate (-50 .. +100 %)
void setRateChange(float newRate);
/// Sets new tempo control value as a difference in percents compared
/// to the original tempo (-50 .. +100 %)
void setTempoChange(float newTempo);
/// Sets new pitch control value. Original pitch = 1.0, smaller values
/// represent lower pitches, larger values higher pitch.
void setPitch(float newPitch);
/// Sets pitch change in octaves compared to the original pitch
/// (-1.00 .. +1.00)
void setPitchOctaves(float newPitch);
/// Sets pitch change in semi-tones compared to the original pitch
/// (-12 .. +12)
void setPitchSemiTones(int newPitch);
void setPitchSemiTones(float newPitch);
/// Sets the number of channels, 1 = mono, 2 = stereo
void setChannels(uint numChannels);
/// Sets sample rate.
void setSampleRate(uint srate);
/// Flushes the last samples from the processing pipeline to the output.
/// Clears also the internal processing buffers.
//
/// Note: This function is meant for extracting the last samples of a sound
/// stream. This function may introduce additional blank samples in the end
/// of the sound stream, and thus it's not recommended to call this function
/// in the middle of a sound stream.
void flush();
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into
/// the input of the object. Notice that sample rate _has_to_ be set before
/// calling this function, otherwise throws a runtime_error exception.
virtual void putSamples(
const SAMPLETYPE *samples, ///< Pointer to sample buffer.
uint numSamples ///< Number of samples in buffer. Notice
///< that in case of stereo-sound a single sample
///< contains data for both channels.
);
/// Clears all the samples in the object's output and internal processing
/// buffers.
virtual void clear();
/// Changes a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's.
///
/// \return 'TRUE' if the setting was succesfully changed
BOOL setSetting(uint settingId, ///< Setting ID number. see SETTING_... defines.
uint value ///< New setting value.
);
/// Reads a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's.
///
/// \return the setting value.
uint getSetting(uint settingId ///< Setting ID number, see SETTING_... defines.
) const;
/// Returns number of samples currently unprocessed.
virtual uint numUnprocessedSamples() const;
/// Other handy functions that are implemented in the ancestor classes (see
/// classes 'FIFOProcessor' and 'FIFOSamplePipe')
///
/// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch.
/// - numSamples() : Get number of 'ready' samples that can be received with
/// function 'receiveSamples()'
/// - isEmpty() : Returns nonzero if there aren't any 'ready' samples.
/// - clear() : Clears all samples from ready/processing buffers.
};
}
#endif

View File

@ -0,0 +1,940 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
/// while maintaining the original pitch by using a time domain WSOLA-like
/// method with several performance-increasing tweaks.
///
/// Note : MMX optimized functions reside in a separate, platform-specific
/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.24 $
//
// $Id: TDStretch.cpp,v 1.24 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <string.h>
#include <stdlib.h>
#include <memory.h>
#include <limits.h>
#include <math.h>
#include <assert.h>
#include "STTypes.h"
#include "cpu_detect.h"
#include "TDStretch.h"
using namespace soundtouch;
#ifndef min
#define min(a,b) ((a > b) ? b : a)
#define max(a,b) ((a < b) ? b : a)
#endif
/*****************************************************************************
*
* Constant definitions
*
*****************************************************************************/
// Table for the hierarchical mixing position seeking algorithm
int scanOffsets[4][24]={
{ 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806,
868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0},
{-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
/*****************************************************************************
*
* Implementation of the class 'TDStretch'
*
*****************************************************************************/
TDStretch::TDStretch() : FIFOProcessor(&outputBuffer)
{
bQuickseek = FALSE;
channels = 2;
bMidBufferDirty = FALSE;
pMidBuffer = NULL;
pRefMidBufferUnaligned = NULL;
overlapLength = 0;
setParameters(48000, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS);
setTempo(1.0f);
}
TDStretch::~TDStretch()
{
delete[] pMidBuffer;
delete[] pRefMidBufferUnaligned;
}
// Calculates the x having the closest 2^x value for the given value
static int _getClosest2Power(double value)
{
return (int)(log(value) / log(2.0) + 0.5);
}
// Sets routine control parameters. These control are certain time constants
// defining how the sound is stretched to the desired duration.
//
// 'sampleRate' = sample rate of the sound
// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms)
// 'seekwindowMS' = seeking window length for scanning the best overlapping
// position (default = 28 ms)
// 'overlapMS' = overlapping length (default = 12 ms)
void TDStretch::setParameters(uint aSampleRate, uint aSequenceMS,
uint aSeekWindowMS, uint aOverlapMS)
{
this->sampleRate = aSampleRate;
this->sequenceMs = aSequenceMS;
this->seekWindowMs = aSeekWindowMS;
this->overlapMs = aOverlapMS;
seekLength = (sampleRate * seekWindowMs) / 1000;
seekWindowLength = (sampleRate * sequenceMs) / 1000;
maxOffset = seekLength;
calculateOverlapLength(overlapMs);
// set tempo to recalculate 'sampleReq'
setTempo(tempo);
}
/// Get routine control parameters, see setParameters() function.
/// Any of the parameters to this function can be NULL, in such case corresponding parameter
/// value isn't returned.
void TDStretch::getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs)
{
if (pSampleRate)
{
*pSampleRate = sampleRate;
}
if (pSequenceMs)
{
*pSequenceMs = sequenceMs;
}
if (pSeekWindowMs)
{
*pSeekWindowMs = seekWindowMs;
}
if (pOverlapMs)
{
*pOverlapMs = overlapMs;
}
}
// Overlaps samples in 'midBuffer' with the samples in 'input'
void TDStretch::overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const
{
int i, itemp;
for (i = 0; i < (int)overlapLength ; i ++)
{
itemp = overlapLength - i;
output[i] = (input[i] * i + pMidBuffer[i] * itemp ) / overlapLength; // >> overlapDividerBits;
}
}
void TDStretch::clearMidBuffer()
{
if (bMidBufferDirty)
{
memset(pMidBuffer, 0, 2 * sizeof(SAMPLETYPE) * overlapLength);
bMidBufferDirty = FALSE;
}
}
void TDStretch::clearInput()
{
inputBuffer.clear();
clearMidBuffer();
}
// Clears the sample buffers
void TDStretch::clear()
{
outputBuffer.clear();
inputBuffer.clear();
clearMidBuffer();
}
// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero
// to enable
void TDStretch::enableQuickSeek(BOOL enable)
{
bQuickseek = enable;
}
// Returns nonzero if the quick seeking algorithm is enabled.
BOOL TDStretch::isQuickSeekEnabled() const
{
return bQuickseek;
}
// Seeks for the optimal overlap-mixing position.
uint TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos)
{
if (channels == 2)
{
// stereo sound
if (bQuickseek)
{
return seekBestOverlapPositionStereoQuick(refPos);
}
else
{
return seekBestOverlapPositionStereo(refPos);
}
}
else
{
// mono sound
if (bQuickseek)
{
return seekBestOverlapPositionMonoQuick(refPos);
}
else
{
return seekBestOverlapPositionMono(refPos);
}
}
}
// Overlaps samples in 'midBuffer' with the samples in 'inputBuffer' at position
// of 'ovlPos'.
inline void TDStretch::overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const
{
if (channels == 2)
{
// stereo sound
overlapStereo(output, input + 2 * ovlPos);
} else {
// mono sound.
overlapMono(output, input + ovlPos);
}
}
// Seeks for the optimal overlap-mixing position. The 'stereo' version of the
// routine
//
// The best position is determined as the position where the two overlapped
// sample sequences are 'most alike', in terms of the highest cross-correlation
// value over the overlapping period
uint TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos)
{
uint bestOffs;
LONG_SAMPLETYPE bestCorr, corr;
uint i;
// Slopes the amplitudes of the 'midBuffer' samples
precalcCorrReferenceStereo();
bestCorr = INT_MIN;
bestOffs = 0;
// Scans for the best correlation value by testing each possible position
// over the permitted range.
for (i = 0; i < seekLength; i ++)
{
// Calculates correlation value for the mixing position corresponding
// to 'i'
corr = calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer);
// Checks for the highest correlation value
if (corr > bestCorr)
{
bestCorr = corr;
bestOffs = i;
}
}
// clear cross correlation routine state if necessary (is so e.g. in MMX routines).
clearCrossCorrState();
return bestOffs;
}
// Seeks for the optimal overlap-mixing position. The 'stereo' version of the
// routine
//
// The best position is determined as the position where the two overlapped
// sample sequences are 'most alike', in terms of the highest cross-correlation
// value over the overlapping period
uint TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos)
{
uint j;
uint bestOffs;
LONG_SAMPLETYPE bestCorr, corr;
uint scanCount, corrOffset, tempOffset;
// Slopes the amplitude of the 'midBuffer' samples
precalcCorrReferenceStereo();
bestCorr = INT_MIN;
bestOffs = 0;
corrOffset = 0;
tempOffset = 0;
// Scans for the best correlation value using four-pass hierarchical search.
//
// The look-up table 'scans' has hierarchical position adjusting steps.
// In first pass the routine searhes for the highest correlation with
// relatively coarse steps, then rescans the neighbourhood of the highest
// correlation with better resolution and so on.
for (scanCount = 0;scanCount < 4; scanCount ++)
{
j = 0;
while (scanOffsets[scanCount][j])
{
tempOffset = corrOffset + scanOffsets[scanCount][j];
if (tempOffset >= seekLength) break;
// Calculates correlation value for the mixing position corresponding
// to 'tempOffset'
corr = calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer);
// Checks for the highest correlation value
if (corr > bestCorr)
{
bestCorr = corr;
bestOffs = tempOffset;
}
j ++;
}
corrOffset = bestOffs;
}
// clear cross correlation routine state if necessary (is so e.g. in MMX routines).
clearCrossCorrState();
return bestOffs;
}
// Seeks for the optimal overlap-mixing position. The 'mono' version of the
// routine
//
// The best position is determined as the position where the two overlapped
// sample sequences are 'most alike', in terms of the highest cross-correlation
// value over the overlapping period
uint TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos)
{
uint bestOffs;
LONG_SAMPLETYPE bestCorr, corr;
uint tempOffset;
const SAMPLETYPE *compare;
// Slopes the amplitude of the 'midBuffer' samples
precalcCorrReferenceMono();
bestCorr = INT_MIN;
bestOffs = 0;
// Scans for the best correlation value by testing each possible position
// over the permitted range.
for (tempOffset = 0; tempOffset < seekLength; tempOffset ++)
{
compare = refPos + tempOffset;
// Calculates correlation value for the mixing position corresponding
// to 'tempOffset'
corr = calcCrossCorrMono(pRefMidBuffer, compare);
// Checks for the highest correlation value
if (corr > bestCorr)
{
bestCorr = corr;
bestOffs = tempOffset;
}
}
// clear cross correlation routine state if necessary (is so e.g. in MMX routines).
clearCrossCorrState();
return bestOffs;
}
// Seeks for the optimal overlap-mixing position. The 'mono' version of the
// routine
//
// The best position is determined as the position where the two overlapped
// sample sequences are 'most alike', in terms of the highest cross-correlation
// value over the overlapping period
uint TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos)
{
uint j;
uint bestOffs;
LONG_SAMPLETYPE bestCorr, corr;
uint scanCount, corrOffset, tempOffset;
// Slopes the amplitude of the 'midBuffer' samples
precalcCorrReferenceMono();
bestCorr = INT_MIN;
bestOffs = 0;
corrOffset = 0;
tempOffset = 0;
// Scans for the best correlation value using four-pass hierarchical search.
//
// The look-up table 'scans' has hierarchical position adjusting steps.
// In first pass the routine searhes for the highest correlation with
// relatively coarse steps, then rescans the neighbourhood of the highest
// correlation with better resolution and so on.
for (scanCount = 0;scanCount < 4; scanCount ++)
{
j = 0;
while (scanOffsets[scanCount][j])
{
tempOffset = corrOffset + scanOffsets[scanCount][j];
if (tempOffset >= seekLength) break;
// Calculates correlation value for the mixing position corresponding
// to 'tempOffset'
corr = calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer);
// Checks for the highest correlation value
if (corr > bestCorr)
{
bestCorr = corr;
bestOffs = tempOffset;
}
j ++;
}
corrOffset = bestOffs;
}
// clear cross correlation routine state if necessary (is so e.g. in MMX routines).
clearCrossCorrState();
return bestOffs;
}
/// clear cross correlation routine state if necessary
void TDStretch::clearCrossCorrState()
{
// default implementation is empty.
}
// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
// tempo, larger faster tempo.
void TDStretch::setTempo(float newTempo)
{
uint intskip;
tempo = newTempo;
// Calculate ideal skip length (according to tempo value)
nominalSkip = tempo * (seekWindowLength - overlapLength);
skipFract = 0;
intskip = (int)(nominalSkip + 0.5f);
// Calculate how many samples are needed in the 'inputBuffer' to
// process another batch of samples
sampleReq = max(intskip + overlapLength, seekWindowLength) + maxOffset;
}
// Sets the number of channels, 1 = mono, 2 = stereo
void TDStretch::setChannels(uint numChannels)
{
if (channels == numChannels) return;
assert(numChannels == 1 || numChannels == 2);
channels = numChannels;
inputBuffer.setChannels(channels);
outputBuffer.setChannels(channels);
}
// nominal tempo, no need for processing, just pass the samples through
// to outputBuffer
void TDStretch::processNominalTempo()
{
assert(tempo == 1.0f);
if (bMidBufferDirty)
{
// If there are samples in pMidBuffer waiting for overlapping,
// do a single sliding overlapping with them in order to prevent a
// clicking distortion in the output sound
if (inputBuffer.numSamples() < overlapLength)
{
// wait until we've got overlapLength input samples
return;
}
// Mix the samples in the beginning of 'inputBuffer' with the
// samples in 'midBuffer' using sliding overlapping
overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0);
outputBuffer.putSamples(overlapLength);
inputBuffer.receiveSamples(overlapLength);
clearMidBuffer();
// now we've caught the nominal sample flow and may switch to
// bypass mode
}
// Simply bypass samples from input to output
outputBuffer.moveSamples(inputBuffer);
}
// Processes as many processing frames of the samples 'inputBuffer', store
// the result into 'outputBuffer'
void TDStretch::processSamples()
{
uint ovlSkip, offset;
int temp;
/* Removed this small optimization - can introduce a click to sound when tempo setting
crosses the nominal value
if (tempo == 1.0f)
{
// tempo not changed from the original, so bypass the processing
processNominalTempo();
return;
}
*/
if (bMidBufferDirty == FALSE)
{
// if midBuffer is empty, move the first samples of the input stream
// into it
if (inputBuffer.numSamples() < overlapLength)
{
// wait until we've got overlapLength samples
return;
}
memcpy(pMidBuffer, inputBuffer.ptrBegin(), channels * overlapLength * sizeof(SAMPLETYPE));
inputBuffer.receiveSamples(overlapLength);
bMidBufferDirty = TRUE;
}
// Process samples as long as there are enough samples in 'inputBuffer'
// to form a processing frame.
while (inputBuffer.numSamples() >= sampleReq)
{
// If tempo differs from the normal ('SCALE'), scan for the best overlapping
// position
offset = seekBestOverlapPosition(inputBuffer.ptrBegin());
// Mix the samples in the 'inputBuffer' at position of 'offset' with the
// samples in 'midBuffer' using sliding overlapping
// ... first partially overlap with the end of the previous sequence
// (that's in 'midBuffer')
overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), offset);
outputBuffer.putSamples(overlapLength);
// ... then copy sequence samples from 'inputBuffer' to output
temp = (seekWindowLength - 2 * overlapLength);// & 0xfffffffe;
if (temp > 0)
{
outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), temp);
}
// Copies the end of the current sequence from 'inputBuffer' to
// 'midBuffer' for being mixed with the beginning of the next
// processing sequence and so on
assert(offset + seekWindowLength <= inputBuffer.numSamples());
memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + seekWindowLength - overlapLength),
channels * sizeof(SAMPLETYPE) * overlapLength);
bMidBufferDirty = TRUE;
// Remove the processed samples from the input buffer. Update
// the difference between integer & nominal skip step to 'skipFract'
// in order to prevent the error from accumulating over time.
skipFract += nominalSkip; // real skip size
ovlSkip = (int)skipFract; // rounded to integer skip
skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip
inputBuffer.receiveSamples(ovlSkip);
}
}
// Adds 'numsamples' pcs of samples from the 'samples' memory position into
// the input of the object.
void TDStretch::putSamples(const SAMPLETYPE *samples, uint numSamples)
{
// Add the samples into the input buffer
inputBuffer.putSamples(samples, numSamples);
// Process the samples in input buffer
processSamples();
}
/// Set new overlap length parameter & reallocate RefMidBuffer if necessary.
void TDStretch::acceptNewOverlapLength(uint newOverlapLength)
{
uint prevOvl;
prevOvl = overlapLength;
overlapLength = newOverlapLength;
if (overlapLength > prevOvl)
{
delete[] pMidBuffer;
delete[] pRefMidBufferUnaligned;
pMidBuffer = new SAMPLETYPE[overlapLength * 2];
bMidBufferDirty = TRUE;
clearMidBuffer();
pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)];
// ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency
pRefMidBuffer = (SAMPLETYPE *)((((ulongptr)pRefMidBufferUnaligned) + 15) & -16);
}
}
// Operator 'new' is overloaded so that it automatically creates a suitable instance
// depending on if we've a MMX/SSE/etc-capable CPU available or not.
void * TDStretch::operator new(size_t s)
{
// Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead!
assert(FALSE);
return NULL;
}
TDStretch * TDStretch::newInstance()
{
uint uExtensions = 0;
#if !defined(_MSC_VER) || !defined(__x86_64__)
uExtensions = detectCPUextensions();
#endif
// Check if MMX/SSE/3DNow! instruction set extensions supported by CPU
#ifdef ALLOW_MMX
// MMX routines available only with integer sample types
if (uExtensions & SUPPORT_MMX)
{
return ::new TDStretchMMX;
}
else
#endif // ALLOW_MMX
#ifdef ALLOW_SSE
if (uExtensions & SUPPORT_SSE)
{
// SSE support
return ::new TDStretchSSE;
}
else
#endif // ALLOW_SSE
#ifdef ALLOW_3DNOW
if (uExtensions & SUPPORT_3DNOW)
{
// 3DNow! support
return ::new TDStretch3DNow;
}
else
#endif // ALLOW_3DNOW
{
// ISA optimizations not supported, use plain C version
return ::new TDStretch;
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Integer arithmetics specific algorithm implementations.
//
//////////////////////////////////////////////////////////////////////////////
#ifdef INTEGER_SAMPLES
// Slopes the amplitude of the 'midBuffer' samples so that cross correlation
// is faster to calculate
void TDStretch::precalcCorrReferenceStereo()
{
int i, cnt2;
int temp, temp2;
for (i=0 ; i < (int)overlapLength ;i ++)
{
temp = i * (overlapLength - i);
cnt2 = i * 2;
temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider;
pRefMidBuffer[cnt2] = (short)(temp2);
temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider;
pRefMidBuffer[cnt2 + 1] = (short)(temp2);
}
}
// Slopes the amplitude of the 'midBuffer' samples so that cross correlation
// is faster to calculate
void TDStretch::precalcCorrReferenceMono()
{
int i;
long temp;
long temp2;
for (i=0 ; i < (int)overlapLength ;i ++)
{
temp = i * (overlapLength - i);
temp2 = (pMidBuffer[i] * temp) / slopingDivider;
pRefMidBuffer[i] = (short)temp2;
}
}
// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo'
// version of the routine.
void TDStretch::overlapStereo(short *output, const short *input) const
{
int i;
short temp;
uint cnt2;
for (i = 0; i < (int)overlapLength ; i ++)
{
temp = (short)(overlapLength - i);
cnt2 = 2 * i;
output[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength;
output[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength;
}
}
/// Calculates overlap period length in samples.
/// Integer version rounds overlap length to closest power of 2
/// for a divide scaling operation.
void TDStretch::calculateOverlapLength(uint overlapMs)
{
uint newOvl;
overlapDividerBits = _getClosest2Power((sampleRate * overlapMs) / 1000.0);
if (overlapDividerBits > 9) overlapDividerBits = 9;
if (overlapDividerBits < 4) overlapDividerBits = 4;
newOvl = 1<<overlapDividerBits;
acceptNewOverlapLength(newOvl);
// calculate sloping divider so that crosscorrelation operation won't
// overflow 32-bit register. Max. sum of the crosscorrelation sum without
// divider would be 2^30*(N^3-N)/3, where N = overlap length
slopingDivider = (newOvl * newOvl - 1) / 3;
}
long TDStretch::calcCrossCorrMono(const short *mixingPos, const short *compare) const
{
long corr;
uint i;
corr = 0;
for (i = 1; i < overlapLength; i ++)
{
corr += (mixingPos[i] * compare[i]) >> overlapDividerBits;
}
return corr;
}
long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const
{
long corr;
uint i;
corr = 0;
for (i = 2; i < 2 * overlapLength; i += 2)
{
corr += (mixingPos[i] * compare[i] +
mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits;
}
return corr;
}
#endif // INTEGER_SAMPLES
//////////////////////////////////////////////////////////////////////////////
//
// Floating point arithmetics specific algorithm implementations.
//
#ifdef FLOAT_SAMPLES
// Slopes the amplitude of the 'midBuffer' samples so that cross correlation
// is faster to calculate
void TDStretch::precalcCorrReferenceStereo()
{
int i, cnt2;
float temp;
for (i=0 ; i < (int)overlapLength ;i ++)
{
temp = (float)i * (float)(overlapLength - i);
cnt2 = i * 2;
pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp);
pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp);
}
}
// Slopes the amplitude of the 'midBuffer' samples so that cross correlation
// is faster to calculate
void TDStretch::precalcCorrReferenceMono()
{
int i;
float temp;
for (i=0 ; i < (int)overlapLength ;i ++)
{
temp = (float)i * (float)(overlapLength - i);
pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp);
}
}
// SSE-optimized version of the function overlapStereo
void TDStretch::overlapStereo(float *output, const float *input) const
{
int i;
uint cnt2;
float fTemp;
float fScale;
float fi;
fScale = 1.0f / (float)overlapLength;
for (i = 0; i < (int)overlapLength ; i ++)
{
fTemp = (float)(overlapLength - i) * fScale;
fi = (float)i * fScale;
cnt2 = 2 * i;
output[cnt2 + 0] = input[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp;
output[cnt2 + 1] = input[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp;
}
}
/// Calculates overlap period length in samples.
void TDStretch::calculateOverlapLength(uint overlapMs)
{
uint newOvl;
newOvl = (sampleRate * overlapMs) / 1000;
if (newOvl < 16) newOvl = 16;
// must be divisible by 8
newOvl -= newOvl % 8;
acceptNewOverlapLength(newOvl);
}
double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const
{
double corr;
uint i;
corr = 0;
for (i = 1; i < overlapLength; i ++)
{
corr += mixingPos[i] * compare[i];
}
return corr;
}
double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const
{
double corr;
uint i;
corr = 0;
for (i = 2; i < 2 * overlapLength; i += 2)
{
corr += mixingPos[i] * compare[i] +
mixingPos[i + 1] * compare[i + 1];
}
return corr;
}
#endif // FLOAT_SAMPLES

View File

@ -0,0 +1,236 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
/// while maintaining the original pitch by using a time domain WSOLA-like method
/// with several performance-increasing tweaks.
///
/// Note : MMX optimized functions reside in a separate, platform-specific file,
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.16 $
//
// $Id: TDStretch.h,v 1.16 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef TDStretch_H
#define TDStretch_H
#include "STTypes.h"
#include "RateTransposer.h"
#include "FIFOSamplePipe.h"
namespace soundtouch
{
// Default values for sound processing parameters:
/// Default length of a single processing sequence, in milliseconds. This determines to how
/// long sequences the original sound is chopped in the time-stretch algorithm.
///
/// The larger this value is, the lesser sequences are used in processing. In principle
/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo
/// and vice versa.
///
/// Increasing this value reduces computational burden & vice versa.
#define DEFAULT_SEQUENCE_MS 40
#define DEFAULT_SEEKWINDOW_MS 30
#define DEFAULT_OVERLAP_MS 20
/// Class that does the time-stretch (tempo change) effect for the processed
/// sound.
class TDStretch : public FIFOProcessor
{
protected:
uint channels;
uint sampleReq;
float tempo;
SAMPLETYPE *pMidBuffer;
SAMPLETYPE *pRefMidBuffer;
SAMPLETYPE *pRefMidBufferUnaligned;
uint overlapLength;
uint overlapDividerBits;
uint slopingDivider;
uint seekLength;
uint seekWindowLength;
uint maxOffset;
float nominalSkip;
float skipFract;
FIFOSampleBuffer outputBuffer;
FIFOSampleBuffer inputBuffer;
BOOL bQuickseek;
BOOL bMidBufferDirty;
uint sampleRate;
uint sequenceMs;
uint seekWindowMs;
uint overlapMs;
void acceptNewOverlapLength(uint newOverlapLength);
virtual void clearCrossCorrState();
void calculateOverlapLength(uint overlapMs);
virtual LONG_SAMPLETYPE calcCrossCorrStereo(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const;
virtual LONG_SAMPLETYPE calcCrossCorrMono(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const;
virtual uint seekBestOverlapPositionStereo(const SAMPLETYPE *refPos);
virtual uint seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos);
virtual uint seekBestOverlapPositionMono(const SAMPLETYPE *refPos);
virtual uint seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos);
uint seekBestOverlapPosition(const SAMPLETYPE *refPos);
virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const;
virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const;
void clearMidBuffer();
void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const;
void precalcCorrReferenceMono();
void precalcCorrReferenceStereo();
void processNominalTempo();
/// Changes the tempo of the given sound samples.
/// Returns amount of samples returned in the "output" buffer.
/// The maximum amount of samples that can be returned at a time is set by
/// the 'set_returnBuffer_size' function.
void processSamples();
public:
TDStretch();
virtual ~TDStretch();
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we've a MMX/SSE/etc-capable CPU available or not.
void *operator new(size_t s);
/// Use this function instead of "new" operator to create a new instance of this class.
/// This function automatically chooses a correct feature set depending on if the CPU
/// supports MMX/SSE/etc extensions.
static TDStretch *newInstance();
/// Returns the output buffer object
FIFOSamplePipe *getOutput() { return &outputBuffer; };
/// Returns the input buffer object
FIFOSamplePipe *getInput() { return &inputBuffer; };
/// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
/// tempo, larger faster tempo.
void setTempo(float newTempo);
/// Returns nonzero if there aren't any samples available for outputting.
virtual void clear();
/// Clears the input buffer
void clearInput();
/// Sets the number of channels, 1 = mono, 2 = stereo
void setChannels(uint numChannels);
/// Enables/disables the quick position seeking algorithm. Zero to disable,
/// nonzero to enable
void enableQuickSeek(BOOL enable);
/// Returns nonzero if the quick seeking algorithm is enabled.
BOOL isQuickSeekEnabled() const;
/// Sets routine control parameters. These control are certain time constants
/// defining how the sound is stretched to the desired duration.
//
/// 'sampleRate' = sample rate of the sound
/// 'sequenceMS' = one processing sequence length in milliseconds
/// 'seekwindowMS' = seeking window length for scanning the best overlapping
/// position
/// 'overlapMS' = overlapping length
void setParameters(uint sampleRate, ///< Samplerate of sound being processed (Hz)
uint sequenceMS = DEFAULT_SEQUENCE_MS, ///< Single processing sequence length (ms)
uint seekwindowMS = DEFAULT_SEEKWINDOW_MS, ///< Offset seeking window length (ms)
uint overlapMS = DEFAULT_OVERLAP_MS ///< Sequence overlapping length (ms)
);
/// Get routine control parameters, see setParameters() function.
/// Any of the parameters to this function can be NULL, in such case corresponding parameter
/// value isn't returned.
void getParameters(uint *pSampleRate, uint *pSequenceMs, uint *pSeekWindowMs, uint *pOverlapMs);
/// Adds 'numsamples' pcs of samples from the 'samples' memory position into
/// the input of the object.
virtual void putSamples(
const SAMPLETYPE *samples, ///< Input sample data
uint numSamples ///< Number of samples in 'samples' so that one sample
///< contains both channels if stereo
);
};
// Implementation-specific class declarations:
//#ifdef ALLOW_MMX
// /// Class that implements MMX optimized routines for 16bit integer samples type.
// class TDStretchMMX : public TDStretch
// {
// protected:
// long calcCrossCorrStereo(const short *mixingPos, const short *compare) const;
// virtual void overlapStereo(short *output, const short *input) const;
// virtual void clearCrossCorrState();
// };
//#endif /// ALLOW_MMX
//
//
//#ifdef ALLOW_3DNOW
// /// Class that implements 3DNow! optimized routines for floating point samples type.
// class TDStretch3DNow : public TDStretch
// {
// protected:
// double calcCrossCorrStereo(const float *mixingPos, const float *compare) const;
// };
//#endif /// ALLOW_3DNOW
#ifdef ALLOW_SSE
/// Class that implements SSE optimized routines for floating point samples type.
class TDStretchSSE : public TDStretch
{
protected:
double calcCrossCorrStereo(const float *mixingPos, const float *compare) const;
};
#endif /// ALLOW_SSE
}
#endif /// TDStretch_H

View File

@ -0,0 +1,711 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Classes for easy reading & writing of WAV sound files.
///
/// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly
/// parse the WAV files with such processors.
///
/// Admittingly, more complete WAV reader routines may exist in public domain,
/// but the reason for 'yet another' one is that those generic WAV reader
/// libraries are exhaustingly large and cumbersome! Wanted to have something
/// simpler here, i.e. something that's not already larger than rest of the
/// SoundTouch/SoundStretch program...
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.15 $
//
// $Id: WavFile.cpp,v 1.15 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdexcept>
#include <string>
#include <assert.h>
#include <limits.h>
#include "WavFile.h"
using namespace std;
const static char riffStr[] = "RIFF";
const static char waveStr[] = "WAVE";
const static char fmtStr[] = "fmt ";
const static char dataStr[] = "data";
//////////////////////////////////////////////////////////////////////////////
//
// Helper functions for swapping byte order to correctly read/write WAV files
// with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to
// turn-on the conversion if it appears necessary.
//
// For example, Intel x86 is little-endian and doesn't require conversion,
// while PowerPC of Mac's and many other RISC cpu's are big-endian.
#ifdef BYTE_ORDER
// In gcc compiler detect the byte order automatically
#if BYTE_ORDER == BIG_ENDIAN
// big-endian platform.
#define _BIG_ENDIAN_
#endif
#endif
#ifdef _BIG_ENDIAN_
// big-endian CPU, swap bytes in 16 & 32 bit words
// helper-function to swap byte-order of 32bit integer
static inline void _swap32(unsigned int &dwData)
{
dwData = ((dwData >> 24) & 0x000000FF) |
((dwData >> 8) & 0x0000FF00) |
((dwData << 8) & 0x00FF0000) |
((dwData << 24) & 0xFF000000);
}
// helper-function to swap byte-order of 16bit integer
static inline void _swap16(unsigned short &wData)
{
wData = ((wData >> 8) & 0x00FF) |
((wData << 8) & 0xFF00);
}
// helper-function to swap byte-order of buffer of 16bit integers
static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumWords)
{
unsigned long i;
for (i = 0; i < dwNumWords; i ++)
{
_swap16(pData[i]);
}
}
#else // BIG_ENDIAN
// little-endian CPU, WAV file is ok as such
// dummy helper-function
static inline void _swap32(unsigned int &dwData)
{
// do nothing
}
// dummy helper-function
static inline void _swap16(unsigned short &wData)
{
// do nothing
}
// dummy helper-function
static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumBytes)
{
// do nothing
}
#endif // BIG_ENDIAN
//////////////////////////////////////////////////////////////////////////////
//
// Class WavInFile
//
WavInFile::WavInFile(const char *fileName)
{
int hdrsOk;
// Try to open the file for reading
fptr = fopen(fileName, "rb");
if (fptr == NULL)
{
// didn't succeed
string msg = "Error : Unable to open file \"";
msg += fileName;
msg += "\" for reading.";
throw runtime_error(msg);
}
// Read the file headers
hdrsOk = readWavHeaders();
if (hdrsOk != 0)
{
// Something didn't match in the wav file headers
string msg = "File \"";
msg += fileName;
msg += "\" is corrupt or not a WAV file";
throw runtime_error(msg);
}
if (header.format.fixed != 1)
{
string msg = "File \"";
msg += fileName;
msg += "\" uses unsupported encoding.";
throw runtime_error(msg);
}
dataRead = 0;
}
WavInFile::~WavInFile()
{
close();
}
void WavInFile::rewind()
{
int hdrsOk;
fseek(fptr, 0, SEEK_SET);
hdrsOk = readWavHeaders();
assert(hdrsOk == 0);
dataRead = 0;
}
int WavInFile::checkCharTags()
{
// header.format.fmt should equal to 'fmt '
if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1;
// header.data.data_field should equal to 'data'
if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1;
return 0;
}
int WavInFile::read(char *buffer, int maxElems)
{
int numBytes;
uint afterDataRead;
// ensure it's 8 bit format
if (header.format.bits_per_sample != 8)
{
throw runtime_error("Error: WavInFile::read(char*, int) works only with 8bit samples.");
}
assert(sizeof(char) == 1);
numBytes = maxElems;
afterDataRead = dataRead + numBytes;
if (afterDataRead > header.data.data_len)
{
// Don't read more samples than are marked available in header
numBytes = header.data.data_len - dataRead;
assert(numBytes >= 0);
}
numBytes = fread(buffer, 1, numBytes, fptr);
dataRead += numBytes;
return numBytes;
}
int WavInFile::read(short *buffer, int maxElems)
{
unsigned int afterDataRead;
int numBytes;
int numElems;
if (header.format.bits_per_sample == 8)
{
// 8 bit format
char *temp = new char[maxElems];
int i;
numElems = read(temp, maxElems);
// convert from 8 to 16 bit
for (i = 0; i < numElems; i ++)
{
buffer[i] = temp[i] << 8;
}
delete[] temp;
}
else
{
// 16 bit format
assert(header.format.bits_per_sample == 16);
assert(sizeof(short) == 2);
numBytes = maxElems * 2;
afterDataRead = dataRead + numBytes;
if (afterDataRead > header.data.data_len)
{
// Don't read more samples than are marked available in header
numBytes = header.data.data_len - dataRead;
assert(numBytes >= 0);
}
numBytes = fread(buffer, 1, numBytes, fptr);
dataRead += numBytes;
numElems = numBytes / 2;
// 16bit samples, swap byte order if necessary
_swap16Buffer((unsigned short *)buffer, numElems);
}
return numElems;
}
int WavInFile::read(float *buffer, int maxElems)
{
short *temp = new short[maxElems];
int num;
int i;
double fscale;
num = read(temp, maxElems);
fscale = 1.0 / 32768.0;
// convert to floats, scale to range [-1..+1[
for (i = 0; i < num; i ++)
{
buffer[i] = (float)(fscale * (double)temp[i]);
}
delete[] temp;
return num;
}
int WavInFile::eof() const
{
// return true if all data has been read or file eof has reached
return (dataRead == header.data.data_len || feof(fptr));
}
void WavInFile::close()
{
fclose(fptr);
fptr = NULL;
}
// test if character code is between a white space ' ' and little 'z'
static int isAlpha(char c)
{
return (c >= ' ' && c <= 'z') ? 1 : 0;
}
// test if all characters are between a white space ' ' and little 'z'
static int isAlphaStr(char *str)
{
int c;
c = str[0];
while (c)
{
if (isAlpha(c) == 0) return 0;
str ++;
c = str[0];
}
return 1;
}
int WavInFile::readRIFFBlock()
{
fread(&(header.riff), sizeof(WavRiff), 1, fptr);
// swap 32bit data byte order if necessary
_swap32((unsigned int &)header.riff.package_len);
// header.riff.riff_char should equal to 'RIFF');
if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1;
// header.riff.wave should equal to 'WAVE'
if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1;
return 0;
}
int WavInFile::readHeaderBlock()
{
char label[5];
string sLabel;
// lead label string
fread(label, 1, 4, fptr);
label[4] = 0;
if (isAlphaStr(label) == 0) return -1; // not a valid label
// Decode blocks according to their label
if (strcmp(label, fmtStr) == 0)
{
int nLen, nDump;
// 'fmt ' block
memcpy(header.format.fmt, fmtStr, 4);
// read length of the format field
fread(&nLen, sizeof(int), 1, fptr);
// swap byte order if necessary
_swap32((unsigned int &)nLen); // int format_len;
header.format.format_len = nLen;
// calculate how much length differs from expected
nDump = nLen - (sizeof(header.format) - 8);
// if format_len is larger than expected, read only as much data as we've space for
if (nDump > 0)
{
nLen = sizeof(header.format) - 8;
}
// read data
fread(&(header.format.fixed), nLen, 1, fptr);
// swap byte order if necessary
_swap16((unsigned short &)header.format.fixed); // short int fixed;
_swap16((unsigned short &)header.format.channel_number); // short int channel_number;
_swap32((unsigned int &)header.format.sample_rate); // int sample_rate;
_swap32((unsigned int &)header.format.byte_rate); // int byte_rate;
_swap16((unsigned short &)header.format.byte_per_sample); // short int byte_per_sample;
_swap16((unsigned short &)header.format.bits_per_sample); // short int bits_per_sample;
// if format_len is larger than expected, skip the extra data
if (nDump > 0)
{
fseek(fptr, nDump, SEEK_CUR);
}
return 0;
}
else if (strcmp(label, dataStr) == 0)
{
// 'data' block
memcpy(header.data.data_field, dataStr, 4);
fread(&(header.data.data_len), sizeof(uint), 1, fptr);
// swap byte order if necessary
_swap32((unsigned int &)header.data.data_len);
return 1;
}
else
{
uint len, i;
uint temp;
// unknown block
// read length
fread(&len, sizeof(len), 1, fptr);
// scan through the block
for (i = 0; i < len; i ++)
{
fread(&temp, 1, 1, fptr);
if (feof(fptr)) return -1; // unexpected eof
}
}
return 0;
}
int WavInFile::readWavHeaders()
{
int res;
memset(&header, 0, sizeof(header));
res = readRIFFBlock();
if (res) return 1;
// read header blocks until data block is found
do
{
// read header blocks
res = readHeaderBlock();
if (res < 0) return 1; // error in file structure
} while (res == 0);
// check that all required tags are legal
return checkCharTags();
}
uint WavInFile::getNumChannels() const
{
return header.format.channel_number;
}
uint WavInFile::getNumBits() const
{
return header.format.bits_per_sample;
}
uint WavInFile::getBytesPerSample() const
{
return getNumChannels() * getNumBits() / 8;
}
uint WavInFile::getSampleRate() const
{
return header.format.sample_rate;
}
uint WavInFile::getDataSizeInBytes() const
{
return header.data.data_len;
}
uint WavInFile::getNumSamples() const
{
return header.data.data_len / header.format.byte_per_sample;
}
uint WavInFile::getLengthMS() const
{
uint numSamples;
uint sampleRate;
numSamples = getNumSamples();
sampleRate = getSampleRate();
assert(numSamples < UINT_MAX / 1000);
return (1000 * numSamples / sampleRate);
}
//////////////////////////////////////////////////////////////////////////////
//
// Class WavOutFile
//
WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels)
{
bytesWritten = 0;
fptr = fopen(fileName, "wb");
if (fptr == NULL)
{
string msg = "Error : Unable to open file \"";
msg += fileName;
msg += "\" for writing.";
//pmsg = msg.c_str;
throw runtime_error(msg);
}
fillInHeader(sampleRate, bits, channels);
writeHeader();
}
WavOutFile::~WavOutFile()
{
close();
}
void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels)
{
// fill in the 'riff' part..
// copy string 'RIFF' to riff_char
memcpy(&(header.riff.riff_char), riffStr, 4);
// package_len unknown so far
header.riff.package_len = 0;
// copy string 'WAVE' to wave
memcpy(&(header.riff.wave), waveStr, 4);
// fill in the 'format' part..
// copy string 'fmt ' to fmt
memcpy(&(header.format.fmt), fmtStr, 4);
header.format.format_len = 0x10;
header.format.fixed = 1;
header.format.channel_number = (short)channels;
header.format.sample_rate = sampleRate;
header.format.bits_per_sample = (short)bits;
header.format.byte_per_sample = (short)(bits * channels / 8);
header.format.byte_rate = header.format.byte_per_sample * sampleRate;
header.format.sample_rate = sampleRate;
// fill in the 'data' part..
// copy string 'data' to data_field
memcpy(&(header.data.data_field), dataStr, 4);
// data_len unknown so far
header.data.data_len = 0;
}
void WavOutFile::finishHeader()
{
// supplement the file length into the header structure
header.riff.package_len = bytesWritten + 36;
header.data.data_len = bytesWritten;
writeHeader();
}
void WavOutFile::writeHeader()
{
WavHeader hdrTemp;
// swap byte order if necessary
hdrTemp = header;
_swap32((unsigned int &)hdrTemp.riff.package_len);
_swap32((unsigned int &)hdrTemp.format.format_len);
_swap16((unsigned short &)hdrTemp.format.fixed);
_swap16((unsigned short &)hdrTemp.format.channel_number);
_swap32((unsigned int &)hdrTemp.format.sample_rate);
_swap32((unsigned int &)hdrTemp.format.byte_rate);
_swap16((unsigned short &)hdrTemp.format.byte_per_sample);
_swap16((unsigned short &)hdrTemp.format.bits_per_sample);
_swap32((unsigned int &)hdrTemp.data.data_len);
// write the supplemented header in the beginning of the file
fseek(fptr, 0, SEEK_SET);
fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr);
// jump back to the end of the file
fseek(fptr, 0, SEEK_END);
}
void WavOutFile::close()
{
finishHeader();
fclose(fptr);
fptr = NULL;
}
void WavOutFile::write(const char *buffer, int numElems)
{
int res;
if (header.format.bits_per_sample != 8)
{
throw runtime_error("Error: WavOutFile::write(const char*, int) accepts only 8bit samples.");
}
assert(sizeof(char) == 1);
res = fwrite(buffer, 1, numElems, fptr);
if (res != numElems)
{
throw runtime_error("Error while writing to a wav file.");
}
bytesWritten += numElems;
}
void WavOutFile::write(const short *buffer, int numElems)
{
int res;
// 16 bit samples
if (numElems < 1) return; // nothing to do
if (header.format.bits_per_sample == 8)
{
int i;
char *temp = new char[numElems];
// convert from 16bit format to 8bit format
for (i = 0; i < numElems; i ++)
{
temp[i] = buffer[i] >> 8;
}
// write in 8bit format
write(temp, numElems);
delete[] temp;
}
else
{
// 16bit format
unsigned short *pTemp = new unsigned short[numElems];
assert(header.format.bits_per_sample == 16);
// allocate temp buffer to swap byte order if necessary
memcpy(pTemp, buffer, numElems * 2);
_swap16Buffer(pTemp, numElems);
res = fwrite(pTemp, 2, numElems, fptr);
delete[] pTemp;
if (res != numElems)
{
throw runtime_error("Error while writing to a wav file.");
}
bytesWritten += 2 * numElems;
}
}
void WavOutFile::write(const float *buffer, int numElems)
{
int i;
short *temp = new short[numElems];
int iTemp;
// convert to 16 bit integer
for (i = 0; i < numElems; i ++)
{
// convert to integer
iTemp = (int)(32768.0f * buffer[i]);
// saturate
if (iTemp < -32768) iTemp = -32768;
if (iTemp > 32767) iTemp = 32767;
temp[i] = (short)iTemp;
}
write(temp, numElems);
delete[] temp;
}

View File

@ -0,0 +1,253 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Classes for easy reading & writing of WAV sound files.
///
/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly
/// parse the WAV files with such processors.
///
/// Admittingly, more complete WAV reader routines may exist in public domain, but
/// the reason for 'yet another' one is that those generic WAV reader libraries are
/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e.
/// something that's not already larger than rest of the SoundTouch/SoundStretch program...
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.7 $
//
// $Id: WavFile.h,v 1.7 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef WAVFILE_H
#define WAVFILE_H
#include <stdio.h>
#ifndef uint
typedef unsigned int uint;
#endif
/// WAV audio file 'riff' section header
typedef struct
{
char riff_char[4];
int package_len;
char wave[4];
} WavRiff;
/// WAV audio file 'format' section header
typedef struct
{
char fmt[4];
int format_len;
short fixed;
short channel_number;
int sample_rate;
int byte_rate;
short byte_per_sample;
short bits_per_sample;
} WavFormat;
/// WAV audio file 'data' section header
typedef struct
{
char data_field[4];
uint data_len;
} WavData;
/// WAV audio file header
typedef struct
{
WavRiff riff;
WavFormat format;
WavData data;
} WavHeader;
/// Class for reading WAV audio files.
class WavInFile
{
private:
/// File pointer.
FILE *fptr;
/// Counter of how many bytes of sample data have been read from the file.
uint dataRead;
/// WAV header information
WavHeader header;
/// Read WAV file headers.
/// \return zero if all ok, nonzero if file format is invalid.
int readWavHeaders();
/// Checks WAV file header tags.
/// \return zero if all ok, nonzero if file format is invalid.
int checkCharTags();
/// Reads a single WAV file header block.
/// \return zero if all ok, nonzero if file format is invalid.
int readHeaderBlock();
/// Reads WAV file 'riff' block
int readRIFFBlock();
public:
/// Constructor: Opens the given WAV file. If the file can't be opened,
/// throws 'runtime_error' exception.
WavInFile(const char *filename);
/// Destructor: Closes the file.
~WavInFile();
/// Close the file. Notice that file is automatically closed also when the
/// class instance is deleted.
void close();
/// Rewind to beginning of the file
void rewind();
/// Get sample rate.
uint getSampleRate() const;
/// Get number of bits per sample, i.e. 8 or 16.
uint getNumBits() const;
/// Get sample data size in bytes. Ahem, this should return same information as
/// 'getBytesPerSample'...
uint getDataSizeInBytes() const;
/// Get total number of samples in file.
uint getNumSamples() const;
/// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample)
uint getBytesPerSample() const;
/// Get number of audio channels in the file (1=mono, 2=stereo)
uint getNumChannels() const;
/// Get the audio file length in milliseconds
uint getLengthMS() const;
/// Reads audio samples from the WAV file. This routine works only for 8 bit samples.
/// Reads given number of elements from the file or if end-of-file reached, as many
/// elements as are left in the file.
///
/// \return Number of 8-bit integers read from the file.
int read(char *buffer, int maxElems);
/// Reads audio samples from the WAV file to 16 bit integer format. Reads given number
/// of elements from the file or if end-of-file reached, as many elements as are
/// left in the file.
///
/// \return Number of 16-bit integers read from the file.
int read(short *buffer, ///< Pointer to buffer where to read data.
int maxElems ///< Size of 'buffer' array (number of array elements).
);
/// Reads audio samples from the WAV file to floating point format, converting
/// sample values to range [-1,1[. Reads given number of elements from the file
/// or if end-of-file reached, as many elements as are left in the file.
///
/// \return Number of elements read from the file.
int read(float *buffer, ///< Pointer to buffer where to read data.
int maxElems ///< Size of 'buffer' array (number of array elements).
);
/// Check end-of-file.
///
/// \return Nonzero if end-of-file reached.
int eof() const;
};
/// Class for writing WAV audio files.
class WavOutFile
{
private:
/// Pointer to the WAV file
FILE *fptr;
/// WAV file header data.
WavHeader header;
/// Counter of how many bytes have been written to the file so far.
int bytesWritten;
/// Fills in WAV file header information.
void fillInHeader(const uint sampleRate, const uint bits, const uint channels);
/// Finishes the WAV file header by supplementing information of amount of
/// data written to file etc
void finishHeader();
/// Writes the WAV file header.
void writeHeader();
public:
/// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception
/// if file creation fails.
WavOutFile(const char *fileName, ///< Filename
int sampleRate, ///< Sample rate (e.g. 44100 etc)
int bits, ///< Bits per sample (8 or 16 bits)
int channels ///< Number of channels (1=mono, 2=stereo)
);
/// Destructor: Finalizes & closes the WAV file.
~WavOutFile();
/// Write data to WAV file. This function works only with 8bit samples.
/// Throws a 'runtime_error' exception if writing to file fails.
void write(const char *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file.
);
/// Write data to WAV file. Throws a 'runtime_error' exception if writing to
/// file fails.
void write(const short *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file.
);
/// Write data to WAV file in floating point format, saturating sample values to range
/// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails.
void write(const float *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file.
);
/// Finalize & close the WAV file. Automatically supplements the WAV file header
/// information according to written data etc.
///
/// Notice that file is automatically closed also when the class instance is deleted.
void close();
};
#endif

View File

@ -0,0 +1,62 @@
////////////////////////////////////////////////////////////////////////////////
///
/// A header file for detecting the Intel MMX instructions set extension.
///
/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the
/// routine implementations for x86 Windows, x86 gnu version and non-x86
/// platforms, respectively.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.4 $
//
// $Id: cpu_detect.h,v 1.4 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _CPU_DETECT_H_
#define _CPU_DETECT_H_
#include "STTypes.h"
#define SUPPORT_MMX 0x0001
#define SUPPORT_3DNOW 0x0002
#define SUPPORT_ALTIVEC 0x0004
#define SUPPORT_SSE 0x0008
#define SUPPORT_SSE2 0x0010
/// Checks which instruction set extensions are supported by the CPU.
///
/// \return A bitmask of supported extensions, see SUPPORT_... defines.
uint detectCPUextensions(void);
/// Disables given set of instruction extensions. See SUPPORT_... defines.
void disableExtensions(uint wDisableMask);
#endif // _CPU_DETECT_H_

View File

@ -0,0 +1,126 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Win32 version of the x86 CPU detect routine.
///
/// This file is to be compiled in Windows platform with Microsoft Visual C++
/// Compiler. Please see 'cpu_detect_x86_gcc.cpp' for the gcc compiler version
/// for all GNU platforms.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.10 $
//
// $Id: cpu_detect_x86_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include "cpu_detect.h"
#ifndef _WIN32
#error wrong platform - this source code file is exclusively for Win32 platform
#endif
//////////////////////////////////////////////////////////////////////////////
//
// processor instructions extension detection routines
//
//////////////////////////////////////////////////////////////////////////////
// Flag variable indicating whick ISA extensions are disabled (for debugging)
static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions
// Disables given set of instruction extensions. See SUPPORT_... defines.
void disableExtensions(uint dwDisableMask)
{
_dwDisabledISA = dwDisableMask;
}
/// Checks which instruction set extensions are supported by the CPU.
uint detectCPUextensions(void)
{
uint res = 0;
if (_dwDisabledISA == 0xffffffff) return 0;
_asm
{
; check if 'cpuid' instructions is available by toggling eflags bit 21
;
xor esi, esi ; clear esi = result register
pushfd ; save eflags to stack
pop eax ; load eax from stack (with eflags)
mov ecx, eax ; save the original eflags values to ecx
xor eax, 0x00200000 ; toggle bit 21
push eax ; store toggled eflags to stack
popfd ; load eflags from stack
pushfd ; save updated eflags to stack
pop eax ; load from stack
xor edx, edx ; clear edx for defaulting no mmx
cmp eax, ecx ; compare to original eflags values
jz end ; jumps to 'end' if cpuid not present
; cpuid instruction available, test for presence of mmx instructions
mov eax, 1
cpuid
test edx, 0x00800000
jz end ; branch if MMX not available
or esi, SUPPORT_MMX ; otherwise add MMX support bit
test edx, 0x02000000
jz test3DNow ; branch if SSE not available
or esi, SUPPORT_SSE ; otherwise add SSE support bit
test3DNow:
; test for precense of AMD extensions
mov eax, 0x80000000
cpuid
cmp eax, 0x80000000
jbe end ; branch if no AMD extensions detected
; test for precense of 3DNow! extension
mov eax, 0x80000001
cpuid
test edx, 0x80000000
jz end ; branch if 3DNow! not detected
or esi, SUPPORT_3DNOW ; otherwise add 3DNow support bit
end:
mov res, esi
}
return res & ~_dwDisabledISA;
}

View File

@ -0,0 +1,305 @@
////////////////////////////////////////////////////////////////////////////////
///
/// MMX optimized routines. All MMX optimized functions have been gathered into
/// this single source code file, regardless to their class or original source
/// code file, in order to ease porting the library to other compiler and
/// processor platforms.
///
/// The MMX-optimizations are programmed using MMX compiler intrinsics that
/// are supported both by Microsoft Visual C++ and GCC compilers, so this file
/// should compile with both toolsets.
///
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
/// 6.0 processor pack" update to support compiler intrinsic syntax. The update
/// is available for download at Microsoft Developers Network, see here:
/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/06 18:52:43 $
// File revision : $Revision: 1.1 $
//
// $Id: mmx_optimized.cpp,v 1.1 2006/02/06 18:52:43 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include "STTypes.h"
#ifdef ALLOW_MMX
// MMX routines available only with integer sample type
#if !(_WIN32 || __i386__ || __x86_64__)
#error "wrong platform - this source code file is exclusively for x86 platforms"
#endif
using namespace soundtouch;
//////////////////////////////////////////////////////////////////////////////
//
// implementation of MMX optimized functions of class 'TDStretchMMX'
//
//////////////////////////////////////////////////////////////////////////////
#include "TDStretch.h"
#include <mmintrin.h>
#include <limits.h>
// Calculates cross correlation of two buffers
long TDStretchMMX::calcCrossCorrStereo(const short *pV1, const short *pV2) const
{
const __m64 *pVec1, *pVec2;
__m64 shifter;
__m64 accu;
long corr;
uint i;
pVec1 = (__m64*)pV1;
pVec2 = (__m64*)pV2;
shifter = _m_from_int(overlapDividerBits);
accu = _mm_setzero_si64();
// Process 4 parallel sets of 2 * stereo samples each during each
// round to improve CPU-level parallellization.
for (i = 0; i < overlapLength / 8; i ++)
{
__m64 temp;
// dictionary of instructions:
// _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3]
// _mm_add_pi32 : 2*32bit add
// _m_psrad : 32bit right-shift
temp = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]),
_mm_madd_pi16(pVec1[1], pVec2[1]));
accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter));
temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]),
_mm_madd_pi16(pVec1[3], pVec2[3]));
accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter));
pVec1 += 4;
pVec2 += 4;
}
// copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1
// and finally store the result into the variable "corr"
accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32));
corr = _m_to_int(accu);
// Clear MMS state
_m_empty();
return corr;
// Note: Warning about the missing EMMS instruction is harmless
// as it'll be called elsewhere.
}
void TDStretchMMX::clearCrossCorrState()
{
// Clear MMS state
_m_empty();
//_asm EMMS;
}
// MMX-optimized version of the function overlapStereo
void TDStretchMMX::overlapStereo(short *output, const short *input) const
{
const __m64 *pVinput, *pVMidBuf;
__m64 *pVdest;
__m64 mix1, mix2, adder, shifter;
uint i;
pVinput = (const __m64*)input;
pVMidBuf = (const __m64*)pMidBuffer;
pVdest = (__m64*)output;
// mix1 = mixer values for 1st stereo sample
// mix1 = mixer values for 2nd stereo sample
// adder = adder for updating mixer values after each round
mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength);
adder = _mm_set_pi16(1, -1, 1, -1);
mix2 = _mm_add_pi16(mix1, adder);
adder = _mm_add_pi16(adder, adder);
shifter = _m_from_int(overlapDividerBits);
for (i = 0; i < overlapLength / 4; i ++)
{
__m64 temp1, temp2;
// load & shuffle data so that input & mixbuffer data samples are paired
temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r
temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r
// temp = (temp .* mix) >> shifter
temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);
temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);
pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit
// update mix += adder
mix1 = _mm_add_pi16(mix1, adder);
mix2 = _mm_add_pi16(mix2, adder);
// --- second round begins here ---
// load & shuffle data so that input & mixbuffer data samples are paired
temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r
temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r
// temp = (temp .* mix) >> shifter
temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);
temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);
pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit
// update mix += adder
mix1 = _mm_add_pi16(mix1, adder);
mix2 = _mm_add_pi16(mix2, adder);
pVinput += 2;
pVMidBuf += 2;
pVdest += 2;
}
_m_empty(); // clear MMS state
}
//////////////////////////////////////////////////////////////////////////////
//
// implementation of MMX optimized functions of class 'FIRFilter'
//
//////////////////////////////////////////////////////////////////////////////
#include "FIRFilter.h"
FIRFilterMMX::FIRFilterMMX() : FIRFilter()
{
filterCoeffsUnalign = NULL;
}
FIRFilterMMX::~FIRFilterMMX()
{
delete[] filterCoeffsUnalign;
}
// (overloaded) Calculates filter coefficients for MMX routine
void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor)
{
uint i;
FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
// Ensure that filter coeffs array is aligned to 16-byte boundary
delete[] filterCoeffsUnalign;
filterCoeffsUnalign = new short[2 * newLength + 8];
filterCoeffsAlign = (short *)(((ulongptr)filterCoeffsUnalign + 15) & -16);
// rearrange the filter coefficients for mmx routines
for (i = 0;i < length; i += 4)
{
filterCoeffsAlign[2 * i + 0] = coeffs[i + 0];
filterCoeffsAlign[2 * i + 1] = coeffs[i + 2];
filterCoeffsAlign[2 * i + 2] = coeffs[i + 0];
filterCoeffsAlign[2 * i + 3] = coeffs[i + 2];
filterCoeffsAlign[2 * i + 4] = coeffs[i + 1];
filterCoeffsAlign[2 * i + 5] = coeffs[i + 3];
filterCoeffsAlign[2 * i + 6] = coeffs[i + 1];
filterCoeffsAlign[2 * i + 7] = coeffs[i + 3];
}
}
// mmx-optimized version of the filter routine for stereo sound
uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, const uint numSamples) const
{
// Create stack copies of the needed member variables for asm routines :
uint i, j;
__m64 *pVdest = (__m64*)dest;
if (length < 2) return 0;
for (i = 0; i < numSamples / 2; i ++)
{
__m64 accu1;
__m64 accu2;
const __m64 *pVsrc = (const __m64*)src;
const __m64 *pVfilter = (const __m64*)filterCoeffsAlign;
accu1 = accu2 = _mm_setzero_si64();
for (j = 0; j < lengthDiv8 * 2; j ++)
{
__m64 temp1, temp2;
temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0
temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1
accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0
accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1
temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2
accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0
accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1
// accu1 += l2*f2+l0*f0 r2*f2+r0*f0
// += l3*f3+l1*f1 r3*f3+r1*f1
// accu2 += l3*f2+l1*f0 r3*f2+r1*f0
// l4*f3+l2*f1 r4*f3+r2*f1
pVfilter += 2;
pVsrc += 2;
}
// accu >>= resultDivFactor
accu1 = _mm_srai_pi32(accu1, resultDivFactor);
accu2 = _mm_srai_pi32(accu2, resultDivFactor);
// pack 2*2*32bits => 4*16 bits
pVdest[0] = _mm_packs_pi32(accu1, accu2);
src += 4;
pVdest ++;
}
_m_empty(); // clear emms state
return (numSamples & 0xfffffffe) - length;
}
#endif // ALLOW_MMX

View File

@ -0,0 +1,484 @@
////////////////////////////////////////////////////////////////////////////////
///
/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE
/// optimized functions have been gathered into this single source
/// code file, regardless to their class or original source code file, in order
/// to ease porting the library to other compiler and processor platforms.
///
/// The SSE-optimizations are programmed using SSE compiler intrinsics that
/// are supported both by Microsoft Visual C++ and GCC compilers, so this file
/// should compile with both toolsets.
///
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
/// 6.0 processor pack" update to support SSE instruction set. The update is
/// available for download at Microsoft Developers Network, see here:
/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx
///
/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and
/// perform a search with keywords "processor pack".
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2006/02/05 16:44:06 $
// File revision : $Revision: 1.2 $
//
// $Id: sse_optimized.cpp,v 1.2 2006/02/05 16:44:06 Olli Exp $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include "cpu_detect.h"
#include "STTypes.h"
using namespace soundtouch;
#ifdef ALLOW_SSE
// SSE routines available only with float sample type
//////////////////////////////////////////////////////////////////////////////
//
// implementation of SSE optimized functions of class 'TDStretchSSE'
//
//////////////////////////////////////////////////////////////////////////////
#include "TDStretch.h"
#include <xmmintrin.h>
// Calculates cross correlation of two buffers
double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) const
{
uint i;
__m128 vSum, *pVec2;
// Note. It means a major slow-down if the routine needs to tolerate
// unaligned __m128 memory accesses. It's way faster if we can skip
// unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps.
// This can mean up to ~ 10-fold difference (incl. part of which is
// due to skipping every second round for stereo sound though).
//
// Compile-time define ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided
// for choosing if this little cheating is allowed.
#ifdef ALLOW_NONEXACT_SIMD_OPTIMIZATION
// Little cheating allowed, return valid correlation only for
// aligned locations, meaning every second round for stereo sound.
#define _MM_LOAD _mm_load_ps
if (((ulong)pV1) & 15) return -1e50; // skip unaligned locations
#else
// No cheating allowed, use unaligned load & take the resulting
// performance hit.
#define _MM_LOAD _mm_loadu_ps
#endif
// ensure overlapLength is divisible by 8
assert((overlapLength % 8) == 0);
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
// Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not.
pVec2 = (__m128*)pV2;
vSum = _mm_setzero_ps();
// Unroll the loop by factor of 4 * 4 operations
for (i = 0; i < overlapLength / 8; i ++)
{
// vSum += pV1[0..3] * pV2[0..3]
vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1),pVec2[0]));
// vSum += pV1[4..7] * pV2[4..7]
vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 4), pVec2[1]));
// vSum += pV1[8..11] * pV2[8..11]
vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 8), pVec2[2]));
// vSum += pV1[12..15] * pV2[12..15]
vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 12), pVec2[3]));
pV1 += 16;
pVec2 += 4;
}
// return value = vSum[0] + vSum[1] + vSum[2] + vSum[3]
float *pvSum = (float*)&vSum;
return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]);
/* This is approximately corresponding routine in C-language:
double corr;
uint i;
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
corr = 0.0;
for (i = 0; i < overlapLength / 8; i ++)
{
corr += pV1[0] * pV2[0] +
pV1[1] * pV2[1] +
pV1[2] * pV2[2] +
pV1[3] * pV2[3] +
pV1[4] * pV2[4] +
pV1[5] * pV2[5] +
pV1[6] * pV2[6] +
pV1[7] * pV2[7] +
pV1[8] * pV2[8] +
pV1[9] * pV2[9] +
pV1[10] * pV2[10] +
pV1[11] * pV2[11] +
pV1[12] * pV2[12] +
pV1[13] * pV2[13] +
pV1[14] * pV2[14] +
pV1[15] * pV2[15];
pV1 += 16;
pV2 += 16;
}
*/
/* This is corresponding routine in assembler. This may be teeny-weeny bit faster
than intrinsic version, but more difficult to maintain & get compiled on multiple
platforms.
uint overlapLengthLocal = overlapLength;
float corr;
_asm
{
// Very important note: data in 'pV2' _must_ be aligned to
// 16-byte boundary!
// give prefetch hints to CPU of what data are to be needed soonish
// give more aggressive hints on pV1 as that changes while pV2 stays
// same between runs
prefetcht0 [pV1]
prefetcht0 [pV2]
prefetcht0 [pV1 + 32]
mov eax, dword ptr pV1
mov ebx, dword ptr pV2
xorps xmm0, xmm0
mov ecx, overlapLengthLocal
shr ecx, 3 // div by eight
loop1:
prefetcht0 [eax + 64] // give a prefetch hint to CPU what data are to be needed soonish
prefetcht0 [ebx + 32] // give a prefetch hint to CPU what data are to be needed soonish
movups xmm1, [eax]
mulps xmm1, [ebx]
addps xmm0, xmm1
movups xmm2, [eax + 16]
mulps xmm2, [ebx + 16]
addps xmm0, xmm2
prefetcht0 [eax + 96] // give a prefetch hint to CPU what data are to be needed soonish
prefetcht0 [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish
movups xmm3, [eax + 32]
mulps xmm3, [ebx + 32]
addps xmm0, xmm3
movups xmm4, [eax + 48]
mulps xmm4, [ebx + 48]
addps xmm0, xmm4
add eax, 64
add ebx, 64
dec ecx
jnz loop1
// add the four floats of xmm0 together and return the result.
movhlps xmm1, xmm0 // move 3 & 4 of xmm0 to 1 & 2 of xmm1
addps xmm1, xmm0
movaps xmm2, xmm1
shufps xmm2, xmm2, 0x01 // move 2 of xmm2 as 1 of xmm2
addss xmm2, xmm1
movss corr, xmm2
}
return (double)corr;
*/
}
//////////////////////////////////////////////////////////////////////////////
//
// implementation of SSE optimized functions of class 'FIRFilter'
//
//////////////////////////////////////////////////////////////////////////////
#include "FIRFilter.h"
FIRFilterSSE::FIRFilterSSE() : FIRFilter()
{
filterCoeffsUnalign = NULL;
}
FIRFilterSSE::~FIRFilterSSE()
{
delete[] filterCoeffsUnalign;
}
// (overloaded) Calculates filter coefficients for SSE routine
void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor)
{
uint i;
float fDivider;
FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
// Scale the filter coefficients so that it won't be necessary to scale the filtering result
// also rearrange coefficients suitably for 3DNow!
// Ensure that filter coeffs array is aligned to 16-byte boundary
delete[] filterCoeffsUnalign;
filterCoeffsUnalign = new float[2 * newLength + 4];
filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & -16);
fDivider = (float)resultDivider;
// rearrange the filter coefficients for mmx routines
for (i = 0; i < newLength; i ++)
{
filterCoeffsAlign[2 * i + 0] =
filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider;
}
}
// SSE-optimized version of the filter routine for stereo sound
uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const
{
int count = (numSamples - length) & -2;
int j;
assert(count % 2 == 0);
if (count < 2) return 0;
assert((length % 8) == 0);
assert(((unsigned long)filterCoeffsAlign) % 16 == 0);
// filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2'
for (j = 0; j < count; j += 2)
{
const float *pSrc;
const __m128 *pFil;
__m128 sum1, sum2;
uint i;
pSrc = source; // source audio data
pFil = (__m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients
// are aligned to 16-byte boundary
sum1 = sum2 = _mm_setzero_ps();
for (i = 0; i < length / 8; i ++)
{
// Unroll loop for efficiency & calculate filter for 2*2 stereo samples
// at each pass
// sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset
// sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset.
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0]));
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0]));
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1]));
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1]));
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2]));
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2]));
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3]));
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3]));
pSrc += 16;
pFil += 4;
}
// Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need
// to sum the two hi- and lo-floats of these registers together.
// post-shuffle & add the filtered values and store to dest.
_mm_storeu_ps(dest, _mm_add_ps(
_mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2
_mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0
));
source += 4;
dest += 4;
}
// Ideas for further improvement:
// 1. If it could be guaranteed that 'source' were always aligned to 16-byte
// boundary, a faster aligned '_mm_load_ps' instruction could be used.
// 2. If it could be guaranteed that 'dest' were always aligned to 16-byte
// boundary, a faster '_mm_store_ps' instruction could be used.
return (uint)count;
/* original routine in C-language. please notice the C-version has differently
organized coefficients though.
double suml1, suml2;
double sumr1, sumr2;
uint i, j;
for (j = 0; j < count; j += 2)
{
const float *ptr;
const float *pFil;
suml1 = sumr1 = 0.0;
suml2 = sumr2 = 0.0;
ptr = src;
pFil = filterCoeffs;
for (i = 0; i < lengthLocal; i ++)
{
// unroll loop for efficiency.
suml1 += ptr[0] * pFil[0] +
ptr[2] * pFil[2] +
ptr[4] * pFil[4] +
ptr[6] * pFil[6];
sumr1 += ptr[1] * pFil[1] +
ptr[3] * pFil[3] +
ptr[5] * pFil[5] +
ptr[7] * pFil[7];
suml2 += ptr[8] * pFil[0] +
ptr[10] * pFil[2] +
ptr[12] * pFil[4] +
ptr[14] * pFil[6];
sumr2 += ptr[9] * pFil[1] +
ptr[11] * pFil[3] +
ptr[13] * pFil[5] +
ptr[15] * pFil[7];
ptr += 16;
pFil += 8;
}
dest[0] = (float)suml1;
dest[1] = (float)sumr1;
dest[2] = (float)suml2;
dest[3] = (float)sumr2;
src += 4;
dest += 4;
}
*/
/* Similar routine in assembly, again obsoleted due to maintainability
_asm
{
// Very important note: data in 'src' _must_ be aligned to
// 16-byte boundary!
mov edx, count
mov ebx, dword ptr src
mov eax, dword ptr dest
shr edx, 1
loop1:
// "outer loop" : during each round 2*2 output samples are calculated
// give prefetch hints to CPU of what data are to be needed soonish
prefetcht0 [ebx]
prefetcht0 [filterCoeffsLocal]
mov esi, ebx
mov edi, filterCoeffsLocal
xorps xmm0, xmm0
xorps xmm1, xmm1
mov ecx, lengthLocal
loop2:
// "inner loop" : during each round eight FIR filter taps are evaluated for 2*2 samples
prefetcht0 [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish
prefetcht0 [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish
movups xmm2, [esi] // possibly unaligned load
movups xmm3, [esi + 8] // possibly unaligned load
mulps xmm2, [edi]
mulps xmm3, [edi]
addps xmm0, xmm2
addps xmm1, xmm3
movups xmm4, [esi + 16] // possibly unaligned load
movups xmm5, [esi + 24] // possibly unaligned load
mulps xmm4, [edi + 16]
mulps xmm5, [edi + 16]
addps xmm0, xmm4
addps xmm1, xmm5
prefetcht0 [esi + 64] // give a prefetch hint to CPU what data are to be needed soonish
prefetcht0 [edi + 64] // give a prefetch hint to CPU what data are to be needed soonish
movups xmm6, [esi + 32] // possibly unaligned load
movups xmm7, [esi + 40] // possibly unaligned load
mulps xmm6, [edi + 32]
mulps xmm7, [edi + 32]
addps xmm0, xmm6
addps xmm1, xmm7
movups xmm4, [esi + 48] // possibly unaligned load
movups xmm5, [esi + 56] // possibly unaligned load
mulps xmm4, [edi + 48]
mulps xmm5, [edi + 48]
addps xmm0, xmm4
addps xmm1, xmm5
add esi, 64
add edi, 64
dec ecx
jnz loop2
// Now xmm0 and xmm1 both have a filtered 2-channel sample each, but we still need
// to sum the two hi- and lo-floats of these registers together.
movhlps xmm2, xmm0 // xmm2 = xmm2_3 xmm2_2 xmm0_3 xmm0_2
movlhps xmm2, xmm1 // xmm2 = xmm1_1 xmm1_0 xmm0_3 xmm0_2
shufps xmm0, xmm1, 0xe4 // xmm0 = xmm1_3 xmm1_2 xmm0_1 xmm0_0
addps xmm0, xmm2
movaps [eax], xmm0
add ebx, 16
add eax, 16
dec edx
jnz loop1
}
*/
}
#endif // ALLOW_SSE

27
plugins/spu2ghz/TODO.txt Normal file
View File

@ -0,0 +1,27 @@
This list will include all problems I'm aware of,
and all missing features I want to (try to) implement.
Known Issues:
---------------
- Fire Pro Wrestling R - no ingame sound
- Devil Kings has no music
- FFX menu sound
- FFX not going ingame after new game intro
- FFXII beep-stepping
- Some games need adma sped up
- Some games need adma slowed down
- Devil May Cry 2 - ear killing garbage when shooting alot-especially noticable in devil trigger mode
Unfinished features:
--------------------
- Dolby ProLogic II dematrixer
- per module configuration
- output volume slider
Missing features:
-----------------
- new timestretcher
Optional Additions:
-------------------

View File

@ -0,0 +1,878 @@
#include "ginclude.h"
#include "ASIOConvertSamples.h"
#include <math.h>
#if MAC
#define TRUNCATE 0
#elif ASIO_CPU_X86 || ASIO_CPU_SPARC || ASIO_CPU_MIPS
#define TRUNCATE 1
#undef MAXFLOAT
#define MAXFLOAT 0x7fffff00L
#endif
ASIOConvertSamples::ASIOConvertSamples()
{
}
//-------------------------------------------------------------------------------------------
// mono
void ASIOConvertSamples::convertMono8Unsigned(long *source, char *dest, long frames)
{
unsigned char *c = (unsigned char *)source;
unsigned char a;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = c[3];
#else
a = c[0];
#endif
c += 4;
a -= 0x80U;
*++dest = a;
}
}
void ASIOConvertSamples::convertMono8(long *source, char *dest, long frames)
{
char *c = (char *)source;
char a;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = c[3];
#else
a = c[0];
#endif
c += 4;
*++dest = a;
}
}
void ASIOConvertSamples::convertMono16(long *source, short *dest, long frames)
{
#if ASIO_LITTLE_ENDIAN
char* s = (char*)source;
char* d = (char*)dest;
while(--frames >= 0)
{
*d++ = s[3]; // dest big endian, msb first
*d++ = s[2];
s += 4;
}
#else
long l;
source--;
dest--;
while(--frames >= 0)
{
l = *++source;
*++dest = (short)(l >> 16);
}
#endif
}
void ASIOConvertSamples::convertMono24(long *source, char *dest, long frames)
{
// work with chars in order to prevent misalignments
char *s = (char *)source;
char a, b, c;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = s[3]; // msb
b = s[2];
c = s[1]; // lsb
#else
a = s[0];
b = s[1];
c = s[2];
#endif
s += 4;
*++dest = a; // big endian, msb first
*++dest = b;
*++dest = c;
}
}
// small endian
void ASIOConvertSamples::convertMono16SmallEndian(long *source, short *dest, long frames)
{
char *s = (char *)source;
char *d = (char *)dest;
char a, b;
d--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = s[3];
b = s[2];
#else
a = s[0];
b = s[1];
#endif
s += 4;
*++d = b; // dest small endian, lsb first
*++d = a;
}
}
void ASIOConvertSamples::convertMono24SmallEndian(long *source, char *dest, long frames)
{
// work with chars in order to prevent misalignments
char *s = (char *)source;
char a, b, c;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = s[3];
b = s[2];
c = s[1];
#else
a = s[0];
b = s[1];
c = s[2];
#endif
s += 4;
*++dest = c; // lsb first
*++dest = b;
*++dest = a;
}
}
//-------------------------------------------------------------------------------------------
// stereo interleaved
void ASIOConvertSamples::convertStereo8InterleavedUnsigned(long *left, long *right, char *dest, long frames)
{
unsigned char *cl = (unsigned char *)left;
unsigned char *cr = (unsigned char *)right;
unsigned char a, b;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = cl[3];
b = cr[3];
#else
a = cl[0];
b = cr[0];
#endif
cl += 4;
cr += 4;
a -= 0x80U;
b -= 0x80U;
*++dest = a;
*++dest = b;
}
}
void ASIOConvertSamples::convertStereo8Interleaved(long *left, long *right, char *dest, long frames)
{
unsigned char *cl = (unsigned char *)left;
unsigned char *cr = (unsigned char *)right;
unsigned char a, b;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = cl[3];
b = cr[3];
#else
a = cl[0];
b = cr[0];
#endif
cl += 4;
cr += 4;
*++dest = a;
*++dest = b;
}
}
void ASIOConvertSamples::convertStereo16Interleaved(long *left, long *right, short *dest, long frames)
{
#if ASIO_LITTLE_ENDIAN
char* sl = (char*)left;
char* sr = (char*)right;
char* d = (char*)dest;
while(--frames >= 0)
{
*d++ = sl[3]; // msb first
*d++ = sl[2];
*d++ = sr[3];
*d++ = sr[2];
sl += 4;
sr += 4;
}
#else
long l, r;
left--;
right--;
dest--;
while(--frames >= 0)
{
l = *++left;
r = *++right;
*++dest = (short)(l >> 16);
*++dest = (short)(r >> 16);
}
#endif
}
void ASIOConvertSamples::convertStereo24Interleaved(long *left, long *right, char *dest, long frames)
{
// work with chars in order to prevent misalignments
char *sl = (char *)left;
char *sr = (char *)right;
char al, bl, cl, ar, br, cr;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
cl = sl[1];
ar = sr[3];
br = sr[2];
cr = sr[1];
#else
al = sl[0];
bl = sl[1];
cl = sl[2];
ar = sr[0];
br = sr[1];
cr = sr[2];
#endif
sl += 4;
sr += 4;
*++dest = al;
*++dest = bl;
*++dest = cl;
*++dest = ar;
*++dest = br;
*++dest = cr;
}
}
void ASIOConvertSamples::convertStereo16InterleavedSmallEndian(long *left, long *right, short *dest, long frames)
{
char *sl = (char *)left;
char *sr = (char *)right;
char *d = (char *)dest;
char al, bl, ar, br;
d--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
ar = sr[3];
br = sr[2];
#else
al = sl[0];
bl = sl[1];
ar = sr[0];
br = sr[1];
#endif
sl += 4;
sr += 4;
*++d = bl; // lsb first
*++d = al;
*++d = br;
*++d = ar;
}
}
void ASIOConvertSamples::convertStereo24InterleavedSmallEndian(long *left, long *right, char *dest, long frames)
{
// work with chars in order to prevent misalignments
char *sl = (char *)left;
char *sr = (char *)right;
char al, bl, cl, ar, br, cr;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
cl = sl[1];
ar = sr[3];
br = sr[2];
cr = sr[1];
#else
al = sl[0];
bl = sl[1];
cl = sl[2];
ar = sr[0];
br = sr[1];
cr = sr[2];
#endif
sl += 4;
sr += 4;
*++dest = cl;
*++dest = bl;
*++dest = al;
*++dest = cr;
*++dest = br;
*++dest = ar;
}
}
//-------------------------------------------------------------------------------------------
// stereo split
void ASIOConvertSamples::convertStereo8Unsigned(long *left, long *right, char *dLeft, char *dRight, long frames)
{
unsigned char *cl = (unsigned char *)left;
unsigned char *cr = (unsigned char *)right;
unsigned char a, b;
dLeft--;
dRight--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = cl[3];
b = cr[3];
#else
a = cl[0];
b = cr[0];
#endif
cl += 4;
cr += 4;
a -= 0x80U;
b -= 0x80U;
*++dLeft = a;
*++dRight = b;
}
}
void ASIOConvertSamples::convertStereo8(long *left, long *right, char *dLeft, char *dRight, long frames)
{
unsigned char *cl = (unsigned char *)left;
unsigned char *cr = (unsigned char *)right;
unsigned char a, b;
dLeft--;
dRight--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = cl[3];
b = cr[3];
#else
a = cl[0];
b = cr[0];
#endif
cl += 4;
cr += 4;
*++dLeft = a;
*++dRight = b;
}
}
void ASIOConvertSamples::convertStereo16(long *left, long *right, short *dLeft, short *dRight, long frames)
{
#if ASIO_LITTLE_ENDIAN
char* sl = (char*)left;
char* sr = (char*)right;
char* dl = (char*)dLeft;
char* dr = (char*)dRight;
while(--frames >= 0)
{
*dl++ = sl[3]; // msb first
*dl++ = sl[2];
*dr++ = sr[3];
*dr++ = sr[2];
sl += 4;
sr += 4;
}
#else
long l, r;
left--;
right--;
dLeft--;
dRight--;
while(--frames >= 0)
{
l = *++left;
r = *++right;
*++dLeft = (short)(l >> 16);
*++dRight = (short)(r >> 16);
}
#endif
}
void ASIOConvertSamples::convertStereo24(long *left, long *right, char *dLeft, char *dRight, long frames)
{
// work with chars in order to prevent misalignments
char *sl = (char *)left;
char *sr = (char *)right;
char al, bl, cl, ar, br, cr;
dLeft--;
dRight--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
cl = sl[1];
ar = sr[3];
br = sr[2];
cr = sr[1];
#else
al = sl[0];
bl = sl[1];
cl = sl[2];
ar = sr[0];
br = sr[1];
cr = sr[2];
#endif
sl += 4;
sr += 4;
*++dLeft = al;
*++dLeft = bl;
*++dLeft = cl;
*++dRight = ar;
*++dRight = br;
*++dRight = cr;
}
}
// small endian
void ASIOConvertSamples::convertStereo16SmallEndian(long *left, long *right, short *dLeft, short *dRight, long frames)
{
char *sl = (char *)left;
char *sr = (char *)right;
char *dl = (char *)dLeft;
char *dr = (char *)dRight;
char al, bl, ar, br;
dl--;
dr--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
ar = sr[3];
br = sr[2];
#else
al = sl[0];
bl = sl[1];
ar = sr[0];
br = sr[1];
#endif
sl += 4;
sr += 4;
*++dl = bl;
*++dl = al;
*++dr = br;
*++dr = ar;
}
}
void ASIOConvertSamples::convertStereo24SmallEndian(long *left, long *right, char *dLeft, char *dRight, long frames)
{
// work with chars in order to prevent misalignments
char *sl = (char *)left;
char *sr = (char *)right;
char al, bl, cl, ar, br, cr;
dLeft--;
dRight--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
cl = sl[1];
ar = sr[3];
br = sr[2];
cr = sr[1];
#else
al = sl[0];
bl = sl[1];
cl = sl[2];
ar = sr[0];
br = sr[1];
cr = sr[2];
#endif
sl += 4;
sr += 4;
*++dLeft = cl;
*++dLeft = bl;
*++dLeft = al;
*++dRight = cr;
*++dRight = br;
*++dRight = ar;
}
}
//------------------------------------------------------------------------------------------
// in place integer conversions
void ASIOConvertSamples::int32msb16to16inPlace(long *in, long frames)
{
short *d1 = (short *)in;
short* out = d1;
#if ASIO_LITTLE_ENDIAN
d1++;
#endif
while(--frames >= 0)
{
*out++ = *d1;
d1 += 2;
}
}
void ASIOConvertSamples::int32lsb16to16inPlace(long *in, long frames)
{
short *d1 = (short *)in;
short* out = d1;
#if !ASIO_LITTLE_ENDIAN
d1++;
#endif
while(--frames >= 0)
{
*out++ = *d1;
d1 += 2;
}
}
void ASIOConvertSamples::int32msb16shiftedTo16inPlace(long *in, long frames, long shift)
{
short* out = (short*)in;
while(--frames >= 0)
*out++ = (short)(*in++ >> shift);
}
void ASIOConvertSamples::int24msbto16inPlace(unsigned char *in, long frames)
{
short a;
short* out = (short*)in;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = (short)in[2];
a <<= 8;
a |= (in[1] & 0xff);
#else
a = (short)in[0];
a <<= 8;
a |= (in[1] & 0xff);
#endif
*out++ = a;
in += 3;
}
}
//-----------------------------------------------------------------------------------------
void ASIOConvertSamples::shift32(void* buffer, long shiftAmount, long targetByteWidth,
bool revertEndian, long sampleFrames)
{
long a;
long frames = sampleFrames;
long* source = (long*)buffer;
if(revertEndian)
{
reverseEndian(buffer, 4, sampleFrames);
revertEndian = false;
}
if(targetByteWidth == 2)
{
short* dest = (short*)buffer;
short* al = (short*)&a;
#if ASIO_LITTLE_ENDIAN
al++;
#endif
while(--frames >= 0)
{
a = *source++;
a <<= shiftAmount;
*dest++ = *al;
}
}
else if(targetByteWidth == 3)
{
char* dest = (char*)buffer;
source = (long*)buffer;
char* aa = (char*)&a;
while(--frames >= 0)
{
a = *source++;
a <<= shiftAmount;
#if ASIO_LITTLE_ENDIAN
dest[0] = aa[1]; // lsb
dest[1] = aa[2];
dest[2] = aa[3]; // msb
#else
dest[0] = aa[0]; // msb
dest[1] = aa[1];
dest[2] = aa[2]; // lsb
#endif
dest += 3;
}
}
else if(targetByteWidth == 4)
{
long* dest = source;
while(--frames >= 0)
*dest++ = *source++ << shiftAmount;
}
}
void ASIOConvertSamples::reverseEndian(void* buffer, long byteWidth, long frames)
{
char* a = (char*)buffer;
char* b = a;
char c;
if(byteWidth == 2)
{
while(--frames >= 0)
{
c = a[0];
a[0] = a[1];
a[1] = c;
a += 2;
}
}
else if(byteWidth == 3)
{
while(--frames >= 0)
{
c = a[0];
a[0] = a[2];
a[2] = c;
a += 3;
}
}
else if(byteWidth == 4)
{
while(--frames >= 0)
{
c = a[0];
a[0] = a[3];
a[3] = c;
c = a[1];
a[1] = a[2];
a[2] = c;
a += 4;
}
}
else if(byteWidth == 8)
{
while(--frames >= 0)
{
c = a[0];
a[0] = a[7];
a[7] = c;
c = a[1];
a[1] = a[6];
a[6] = c;
c = a[2];
a[2] = a[5];
a[5] = c;
c = a[3];
a[3] = a[4];
a[4] = c;
a += 4;
}
}
}
//-------------------------------------------------------------------------------------------------
void ASIOConvertSamples::int32to16inPlace(void* buffer, long frames)
{
short* in = (short*)buffer;
short* out = in;
#if ASIO_LITTLE_ENDIAN
in++;
#endif
while(--frames >= 0)
{
*out++ = *in;
in += 2;
}
}
void ASIOConvertSamples::int24to16inPlace(void* buffer, long frames)
{
char* from = (char*)buffer;
char* to = from;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
to[0] = from[1];
to[1] = from[2];
#else
to[0] = from[0];
to[1] = from[1];
#endif
from += 3;
to += 2;
}
}
void ASIOConvertSamples::int32to24inPlace(void* buffer, long frames)
{
long* in = (long*)buffer;
char* out = (char*)buffer;
long a;
while(--frames >= 0)
{
a = *in++;
a >>= 8; // 32->24
#if ASIO_LITTLE_ENDIAN
out[0] = (char)a; // lsb
a >>= 8;
out[1] = (char)a;
a >>= 8;
out[2] = (char)a;
#else
out[2] = (char)a; // lsb
a >>= 8;
out[1] = (char)a;
a >>= 8;
out[0] = (char)a;
#endif
out += 3;
}
}
void ASIOConvertSamples::int16to24inPlace(void* buffer, long frames)
{
char* in = (char*)buffer;
char* out = (char*)buffer;
in += frames * 2;
out += frames * 3;
while(--frames >= 0)
{
out -= 3;
in -= 2;
#if ASIO_LITTLE_ENDIAN
out[2] = in[1]; // msb
out[1] = in[0]; // lsb
out[0] = 0;
#else
out[2] = 0;
out[1] = in[1]; // lsb
out[0] = in[0]; // msb
#endif
}
}
void ASIOConvertSamples::int24to32inPlace(void* buffer, long frames)
{
long a, b, c;
char* in = (char*)buffer;
long* out = (long*)buffer;
in += (frames * 3);
out += frames;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = (long)in[-1]; // msb
b = (long)in[-2];
c = (long)in[-3];
#else
a = (long)in[-3]; // msb
b = (long)in[-2];
c = (long)in[-1];
#endif
a <<= 24;
b <<= 16;
b &= 0x00ff0000;
a |= b;
c <<= 8;
c &= 0x0000ff00;
a |= c;
*--out = a;
in -= 3;
}
}
void ASIOConvertSamples::int16to32inPlace(void* buffer, long frames)
{
short* in = (short*)buffer;
long* out = (long*)buffer;
in += frames;
out += frames;
while(--frames >= 0)
*--out = ((long)(*--in)) << 16;
}
//------------------------------------------------------------------------------------------
// float to int
const double fScaler16 = (double)0x7fffL;
const double fScaler24 = (double)0x7fffffL;
const double fScaler32 = (double)0x7fffffffL;
void ASIOConvertSamples::float32toInt16inPlace(float* buffer, long frames)
{
double sc = fScaler16 + .49999;
short* b = (short*)buffer;
while(--frames >= 0)
*b++ = (short)((double)(*buffer++) * sc);
}
void ASIOConvertSamples::float32toInt24inPlace(float* buffer, long frames)
{
double sc = fScaler24 + .49999;
long a;
char* b = (char*)buffer;
char* aa = (char*)&a;
while(--frames >= 0)
{
a = (long)((double)(*buffer++) * sc);
#if ASIO_LITTLE_ENDIAN
*b++ = aa[3];
*b++ = aa[2];
*b++ = aa[1];
#else
*b++ = aa[1];
*b++ = aa[2];
*b++ = aa[3];
#endif
}
}
void ASIOConvertSamples::float32toInt32inPlace(float* buffer, long frames)
{
double sc = fScaler32 + .49999;
long* b = (long*)buffer;
while(--frames >= 0)
*b++ = (long)((double)(*buffer++) * sc);
}

View File

@ -0,0 +1,62 @@
#ifndef __ASIOConvertSamples__
#define __ASIOConvertSamples__
class ASIOConvertSamples
{
public:
ASIOConvertSamples();
~ASIOConvertSamples() {}
// format converters, input 32 bit integer
// mono
void convertMono8(long *source, char *dest, long frames);
void convertMono8Unsigned(long *source, char *dest, long frames);
void convertMono16(long *source, short *dest, long frames);
void convertMono16SmallEndian(long *source, short *dest, long frames);
void convertMono24(long *source, char *dest, long frames);
void convertMono24SmallEndian(long *source, char *dest, long frames);
// stereo interleaved
void convertStereo8Interleaved(long *left, long *right, char *dest, long frames);
void convertStereo8InterleavedUnsigned(long *left, long *right, char *dest, long frames);
void convertStereo16Interleaved(long *left, long *right, short *dest, long frames);
void convertStereo16InterleavedSmallEndian(long *left, long *right, short *dest, long frames);
void convertStereo24Interleaved(long *left, long *right, char *dest, long frames);
void convertStereo24InterleavedSmallEndian(long *left, long *right, char *dest, long frames);
// stereo split
void convertStereo8(long *left, long *right, char *dLeft, char *dRight, long frames);
void convertStereo8Unsigned(long *left, long *right, char *dLeft, char *dRight, long frames);
void convertStereo16(long *left, long *right, short *dLeft, short *dRight, long frames);
void convertStereo16SmallEndian(long *left, long *right, short *dLeft, short *dRight, long frames);
void convertStereo24(long *left, long *right, char *dLeft, char *dRight, long frames);
void convertStereo24SmallEndian(long *left, long *right, char *dLeft, char *dRight, long frames);
// integer in place conversions
void int32msb16to16inPlace(long *in, long frames);
void int32lsb16to16inPlace(long *in, long frames);
void int32msb16shiftedTo16inPlace(long *in1, long frames, long shift);
void int24msbto16inPlace(unsigned char *in, long frames);
// integer to integer
void shift32(void* buffer, long shiftAmount, long targetByteWidth,
bool reverseEndian, long frames);
void reverseEndian(void* buffer, long byteWidth, long frames);
void int32to16inPlace(void* buffer, long frames);
void int24to16inPlace(void* buffer, long frames);
void int32to24inPlace(void* buffer, long frames);
void int16to24inPlace(void* buffer, long frames);
void int24to32inPlace(void* buffer, long frames);
void int16to32inPlace(void* buffer, long frames);
// float to integer
void float32toInt16inPlace(float* buffer, long frames);
void float32toInt24inPlace(float* buffer, long frames);
void float32toInt32inPlace(float* buffer, long frames);
};
#endif

View File

@ -0,0 +1,257 @@
/*
Steinberg Audio Stream I/O API
(c) 1996, Steinberg Soft- und Hardware GmbH
asio.cpp
asio functions entries which translate the
asio interface to the asiodrvr class methods
*/
#include <string.h>
#include "asiosys.h" // platform definition
#include "asio.h"
#if MAC
#include "asiodrvr.h"
#pragma export on
AsioDriver *theAsioDriver = 0;
extern "C"
{
long main()
{
return 'ASIO';
}
#elif WINDOWS
#include "windows.h"
#include "iasiodrv.h"
#include "asiodrivers.h"
IASIO *theAsioDriver = 0;
//extern AsioDrivers *asioDrivers;
#elif SGI || SUN || BEOS || LINUX
#include "asiodrvr.h"
static AsioDriver *theAsioDriver = 0;
#endif
//-----------------------------------------------------------------------------------------------------
ASIOError ASIOInit(ASIODriverInfo *info)
{
#if MAC || SGI || SUN || BEOS || LINUX
if(theAsioDriver)
{
delete theAsioDriver;
theAsioDriver = 0;
}
info->driverVersion = 0;
strcpy(info->name, "No ASIO Driver");
theAsioDriver = getDriver();
if(!theAsioDriver)
{
strcpy(info->errorMessage, "Not enough memory for the ASIO driver!");
return ASE_NotPresent;
}
if(!theAsioDriver->init(info->sysRef))
{
theAsioDriver->getErrorMessage(info->errorMessage);
delete theAsioDriver;
theAsioDriver = 0;
return ASE_NotPresent;
}
strcpy(info->errorMessage, "No ASIO Driver Error");
theAsioDriver->getDriverName(info->name);
info->driverVersion = theAsioDriver->getDriverVersion();
return ASE_OK;
#else
info->driverVersion = 0;
strcpy(info->name, "No ASIO Driver");
if(theAsioDriver) // must be loaded!
{
if(!theAsioDriver->init(info->sysRef))
{
theAsioDriver->getErrorMessage(info->errorMessage);
theAsioDriver = 0;
return ASE_NotPresent;
}
strcpy(info->errorMessage, "No ASIO Driver Error");
theAsioDriver->getDriverName(info->name);
info->driverVersion = theAsioDriver->getDriverVersion();
return ASE_OK;
}
return ASE_NotPresent;
#endif // !MAC
}
ASIOError ASIOExit(void)
{
if(theAsioDriver)
{
#if WINDOWS
//asioDrivers->removeCurrentDriver();
#else
delete theAsioDriver;
#endif
}
theAsioDriver = 0;
return ASE_OK;
}
ASIOError ASIOStart(void)
{
if(!theAsioDriver)
return ASE_NotPresent;
return theAsioDriver->start();
}
ASIOError ASIOStop(void)
{
if(!theAsioDriver)
return ASE_NotPresent;
return theAsioDriver->stop();
}
ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels)
{
if(!theAsioDriver)
{
*numInputChannels = *numOutputChannels = 0;
return ASE_NotPresent;
}
return theAsioDriver->getChannels(numInputChannels, numOutputChannels);
}
ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency)
{
if(!theAsioDriver)
{
*inputLatency = *outputLatency = 0;
return ASE_NotPresent;
}
return theAsioDriver->getLatencies(inputLatency, outputLatency);
}
ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity)
{
if(!theAsioDriver)
{
*minSize = *maxSize = *preferredSize = *granularity = 0;
return ASE_NotPresent;
}
return theAsioDriver->getBufferSize(minSize, maxSize, preferredSize, granularity);
}
ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate)
{
if(!theAsioDriver)
return ASE_NotPresent;
return theAsioDriver->canSampleRate(sampleRate);
}
ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate)
{
if(!theAsioDriver)
return ASE_NotPresent;
return theAsioDriver->getSampleRate(currentRate);
}
ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate)
{
if(!theAsioDriver)
return ASE_NotPresent;
return theAsioDriver->setSampleRate(sampleRate);
}
ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources)
{
if(!theAsioDriver)
{
*numSources = 0;
return ASE_NotPresent;
}
return theAsioDriver->getClockSources(clocks, numSources);
}
ASIOError ASIOSetClockSource(long reference)
{
if(!theAsioDriver)
return ASE_NotPresent;
return theAsioDriver->setClockSource(reference);
}
ASIOError ASIOGetSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp)
{
if(!theAsioDriver)
return ASE_NotPresent;
return theAsioDriver->getSamplePosition(sPos, tStamp);
}
ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info)
{
if(!theAsioDriver)
{
info->channelGroup = -1;
info->type = ASIOSTInt16MSB;
strcpy(info->name, "None");
return ASE_NotPresent;
}
return theAsioDriver->getChannelInfo(info);
}
ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels,
long bufferSize, ASIOCallbacks *callbacks)
{
if(!theAsioDriver)
{
ASIOBufferInfo *info = bufferInfos;
for(long i = 0; i < numChannels; i++, info++)
info->buffers[0] = info->buffers[1] = 0;
return ASE_NotPresent;
}
return theAsioDriver->createBuffers(bufferInfos, numChannels, bufferSize, callbacks);
}
ASIOError ASIODisposeBuffers(void)
{
if(!theAsioDriver)
return ASE_NotPresent;
return theAsioDriver->disposeBuffers();
}
ASIOError ASIOControlPanel(void)
{
if(!theAsioDriver)
return ASE_NotPresent;
return theAsioDriver->controlPanel();
}
ASIOError ASIOFuture(long selector, void *opt)
{
if(!theAsioDriver)
return ASE_NotPresent;
return theAsioDriver->future(selector, opt);
}
ASIOError ASIOOutputReady(void)
{
if(!theAsioDriver)
return ASE_NotPresent;
return theAsioDriver->outputReady();
}
#if MAC
} // extern "C"
#pragma export off
#endif

1057
plugins/spu2ghz/asio/asio.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,173 @@
#include <string.h>
#include "asiodrivers.h"
//------------------------------------------------------------------------------------
#if MAC
bool resolveASIO(unsigned long aconnID);
AsioDrivers::AsioDrivers() : CodeFragments("ASIO Drivers", 'AsDr', 'Asio')
{
connID = -1;
curIndex = -1;
}
AsioDrivers::~AsioDrivers()
{
removeCurrentDriver();
}
bool AsioDrivers::getCurrentDriverName(char *name)
{
if(curIndex >= 0)
return getName(curIndex, name);
return false;
}
long AsioDrivers::getDriverNames(char **names, long maxDrivers)
{
for(long i = 0; i < getNumFragments() && i < maxDrivers; i++)
getName(i, names[i]);
return getNumFragments() < maxDrivers ? getNumFragments() : maxDrivers;
}
bool AsioDrivers::loadDriver(char *name)
{
char dname[64];
unsigned long newID;
for(long i = 0; i < getNumFragments(); i++)
{
if(getName(i, dname) && !strcmp(name, dname))
{
if(newInstance(i, &newID))
{
if(resolveASIO(newID))
{
if(connID != -1)
removeInstance(curIndex, connID);
curIndex = i;
connID = newID;
return true;
}
}
break;
}
}
return false;
}
void AsioDrivers::removeCurrentDriver()
{
if(connID != -1)
removeInstance(curIndex, connID);
connID = -1;
curIndex = -1;
}
//------------------------------------------------------------------------------------
#elif WINDOWS
#include "iasiodrv.h"
extern IASIO* theAsioDriver;
AsioDrivers::AsioDrivers() : AsioDriverList()
{
curIndex = -1;
}
AsioDrivers::~AsioDrivers()
{
}
bool AsioDrivers::getCurrentDriverName(char *name)
{
if(curIndex >= 0)
return asioGetDriverName(curIndex, name, 32) == 0 ? true : false;
name[0] = 0;
return false;
}
long AsioDrivers::getDriverNames(char **names, long maxDrivers)
{
for(long i = 0; i < asioGetNumDev() && i < maxDrivers; i++)
asioGetDriverName(i, names[i], 32);
return asioGetNumDev() < maxDrivers ? asioGetNumDev() : maxDrivers;
}
bool AsioDrivers::loadDriver(char *name)
{
char dname[64];
char curName[64];
for(long i = 0; i < asioGetNumDev(); i++)
{
if(!asioGetDriverName(i, dname, 32) && !strcmp(name, dname))
{
curName[0] = 0;
getCurrentDriverName(curName); // in case we fail...
removeCurrentDriver();
if(!asioOpenDriver(i, (void **)&theAsioDriver))
{
curIndex = i;
return true;
}
else
{
theAsioDriver = 0;
if(curName[0] && strcmp(dname, curName))
loadDriver(curName); // try restore
}
break;
}
}
return false;
}
void AsioDrivers::removeCurrentDriver()
{
if(curIndex != -1)
asioCloseDriver(curIndex);
curIndex = -1;
}
#elif SGI || BEOS
#include "asiolist.h"
AsioDrivers::AsioDrivers()
: AsioDriverList()
{
curIndex = -1;
}
AsioDrivers::~AsioDrivers()
{
}
bool AsioDrivers::getCurrentDriverName(char *name)
{
return false;
}
long AsioDrivers::getDriverNames(char **names, long maxDrivers)
{
return 0;
}
bool AsioDrivers::loadDriver(char *name)
{
return false;
}
void AsioDrivers::removeCurrentDriver()
{
}
#else
#error implement me
#endif

View File

@ -0,0 +1,41 @@
#ifndef __AsioDrivers__
#define __AsioDrivers__
#include "ginclude.h"
#if MAC
#include "CodeFragments.hpp"
class AsioDrivers : public CodeFragments
#elif WINDOWS
#include <windows.h>
#include "asiolist.h"
class AsioDrivers : public AsioDriverList
#elif SGI || BEOS
#include "asiolist.h"
class AsioDrivers : public AsioDriverList
#else
#error implement me
#endif
{
public:
AsioDrivers();
~AsioDrivers();
bool getCurrentDriverName(char *name);
long getDriverNames(char **names, long maxDrivers);
bool loadDriver(char *name);
void removeCurrentDriver();
long getCurrentDriverIndex() {return curIndex;}
protected:
unsigned long connID;
long curIndex;
};
#endif

View File

@ -0,0 +1,139 @@
/*
Steinberg Audio Stream I/O API
(c) 1996, Steinberg Soft- und Hardware GmbH
charlie (May 1996)
asiodrvr.cpp
c++ superclass to implement asio functionality. from this,
you can derive whatever required
*/
#include <string.h>
#include "asiosys.h"
#include "asiodrvr.h"
#if WINDOWS
#error do not use this
AsioDriver::AsioDriver (LPUNKNOWN pUnk, HRESULT *phr) : CUnknown("My AsioDriver", pUnk, phr)
{
}
#else
AsioDriver::AsioDriver()
{
}
#endif
AsioDriver::~AsioDriver()
{
}
ASIOBool AsioDriver::init(void *sysRef)
{
return ASE_NotPresent;
}
void AsioDriver::getDriverName(char *name)
{
strcpy(name, "No Driver");
}
long AsioDriver::getDriverVersion()
{
return 0;
}
void AsioDriver::getErrorMessage(char *string)
{
strcpy(string, "ASIO Driver Implementation Error!");
}
ASIOError AsioDriver::start()
{
return ASE_NotPresent;
}
ASIOError AsioDriver::stop()
{
return ASE_NotPresent;
}
ASIOError AsioDriver::getChannels(long *numInputChannels, long *numOutputChannels)
{
return ASE_NotPresent;
}
ASIOError AsioDriver::getLatencies(long *inputLatency, long *outputLatency)
{
return ASE_NotPresent;
}
ASIOError AsioDriver::getBufferSize(long *minSize, long *maxSize,
long *preferredSize, long *granularity)
{
return ASE_NotPresent;
}
ASIOError AsioDriver::canSampleRate(ASIOSampleRate sampleRate)
{
return ASE_NotPresent;
}
ASIOError AsioDriver::getSampleRate(ASIOSampleRate *sampleRate)
{
return ASE_NotPresent;
}
ASIOError AsioDriver::setSampleRate(ASIOSampleRate sampleRate)
{
return ASE_NotPresent;
}
ASIOError AsioDriver::getClockSources(ASIOClockSource *clocks, long *numSources)
{
*numSources = 0;
return ASE_NotPresent;
}
ASIOError AsioDriver::setClockSource(long reference)
{
return ASE_NotPresent;
}
ASIOError AsioDriver::getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp)
{
return ASE_NotPresent;
}
ASIOError AsioDriver::getChannelInfo(ASIOChannelInfo *info)
{
return ASE_NotPresent;
}
ASIOError AsioDriver::createBuffers(ASIOBufferInfo *channelInfos, long numChannels,
long bufferSize, ASIOCallbacks *callbacks)
{
return ASE_NotPresent;
}
ASIOError AsioDriver::disposeBuffers()
{
return ASE_NotPresent;
}
ASIOError AsioDriver::controlPanel()
{
return ASE_NotPresent;
}
ASIOError AsioDriver::future(long selector, void *opt)
{
return ASE_NotPresent;
}
ASIOError AsioDriver::outputReady()
{
return ASE_NotPresent;
}

View File

@ -0,0 +1,76 @@
/*
Steinberg Audio Stream I/O API
(c) 1996, Steinberg Soft- und Hardware GmbH
charlie (May 1996)
asiodrvr.h
c++ superclass to implement asio functionality. from this,
you can derive whatever required
*/
#ifndef _asiodrvr_
#define _asiodrvr_
// cpu and os system we are running on
#include "asiosys.h"
// basic "C" interface
#include "asio.h"
class AsioDriver;
extern AsioDriver *getDriver(); // for generic constructor
#if WINDOWS
#include <windows.h>
#include "combase.h"
#include "iasiodrv.h"
class AsioDriver : public IASIO ,public CUnknown
{
public:
AsioDriver(LPUNKNOWN pUnk, HRESULT *phr);
DECLARE_IUNKNOWN
// Factory method
static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
// IUnknown
virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid,void **ppvObject);
#else
class AsioDriver
{
public:
AsioDriver();
#endif
virtual ~AsioDriver();
virtual ASIOBool init(void* sysRef);
virtual void getDriverName(char *name); // max 32 bytes incl. terminating zero
virtual long getDriverVersion();
virtual void getErrorMessage(char *string); // max 124 bytes incl.
virtual ASIOError start();
virtual ASIOError stop();
virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels);
virtual ASIOError getLatencies(long *inputLatency, long *outputLatency);
virtual ASIOError getBufferSize(long *minSize, long *maxSize,
long *preferredSize, long *granularity);
virtual ASIOError canSampleRate(ASIOSampleRate sampleRate);
virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate);
virtual ASIOError setSampleRate(ASIOSampleRate sampleRate);
virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources);
virtual ASIOError setClockSource(long reference);
virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp);
virtual ASIOError getChannelInfo(ASIOChannelInfo *info);
virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels,
long bufferSize, ASIOCallbacks *callbacks);
virtual ASIOError disposeBuffers();
virtual ASIOError controlPanel();
virtual ASIOError future(long selector, void *opt);
virtual ASIOError outputReady();
};
#endif

View File

@ -0,0 +1,268 @@
#include <windows.h>
#include "iasiodrv.h"
#include "asiolist.h"
#define ASIODRV_DESC "description"
#define INPROC_SERVER "InprocServer32"
#define ASIO_PATH "software\\asio"
#define COM_CLSID "clsid"
// ******************************************************************
// Local Functions
// ******************************************************************
static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize)
{
HKEY hkEnum,hksub,hkpath;
char databuf[512];
LONG cr,rc = -1;
DWORD datatype,datasize;
DWORD index;
OFSTRUCT ofs;
HFILE hfile;
BOOL found = FALSE;
CharLowerBuff(clsidstr,strlen(clsidstr));
if ((cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) {
index = 0;
while (cr == ERROR_SUCCESS && !found) {
cr = RegEnumKey(hkEnum,index++,(LPTSTR)databuf,512);
if (cr == ERROR_SUCCESS) {
CharLowerBuff(databuf,strlen(databuf));
if (!(strcmp(databuf,clsidstr))) {
if ((cr = RegOpenKeyEx(hkEnum,(LPCTSTR)databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {
if ((cr = RegOpenKeyEx(hksub,(LPCTSTR)INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) {
datatype = REG_SZ; datasize = (DWORD)dllpathsize;
cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize);
if (cr == ERROR_SUCCESS) {
memset(&ofs,0,sizeof(OFSTRUCT));
ofs.cBytes = sizeof(OFSTRUCT);
hfile = OpenFile(dllpath,&ofs,OF_EXIST);
if (hfile) rc = 0;
}
RegCloseKey(hkpath);
}
RegCloseKey(hksub);
}
found = TRUE; // break out
}
}
}
RegCloseKey(hkEnum);
}
return rc;
}
static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv)
{
HKEY hksub;
char databuf[256];
char dllpath[MAXPATHLEN];
WORD wData[100];
CLSID clsid;
DWORD datatype,datasize;
LONG cr,rc;
if (!lpdrv) {
if ((cr = RegOpenKeyEx(hkey,(LPCTSTR)keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {
datatype = REG_SZ; datasize = 256;
cr = RegQueryValueEx(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize);
if (cr == ERROR_SUCCESS) {
rc = findDrvPath (databuf,dllpath,MAXPATHLEN);
if (rc == 0) {
lpdrv = new ASIODRVSTRUCT[1];
if (lpdrv) {
memset(lpdrv,0,sizeof(ASIODRVSTRUCT));
lpdrv->drvID = drvID;
MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100);
if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) {
memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID));
}
datatype = REG_SZ; datasize = 256;
cr = RegQueryValueEx(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize);
if (cr == ERROR_SUCCESS) {
strncpy(lpdrv->drvname,databuf,127);
}
else strcpy(lpdrv->drvname,keyname);
}
}
}
RegCloseKey(hksub);
}
}
else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next);
return lpdrv;
}
static void deleteDrvStruct (LPASIODRVSTRUCT lpdrv)
{
IASIO *iasio;
if (lpdrv != 0) {
deleteDrvStruct(lpdrv->next);
if (lpdrv->asiodrv) {
iasio = (IASIO *)lpdrv->asiodrv;
iasio->Release();
}
delete lpdrv;
}
}
static LPASIODRVSTRUCT getDrvStruct (int drvID,LPASIODRVSTRUCT lpdrv)
{
while (lpdrv) {
if (lpdrv->drvID == drvID) return lpdrv;
lpdrv = lpdrv->next;
}
return 0;
}
// ******************************************************************
// ******************************************************************
// AsioDriverList
// ******************************************************************
AsioDriverList::AsioDriverList ()
{
HKEY hkEnum = 0;
char keyname[MAXDRVNAMELEN];
LPASIODRVSTRUCT pdl;
LONG cr;
DWORD index = 0;
BOOL fin = FALSE;
numdrv = 0;
lpdrvlist = 0;
cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum);
while (cr == ERROR_SUCCESS) {
if ((cr = RegEnumKey(hkEnum,index++,(LPTSTR)keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) {
lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist);
}
else fin = TRUE;
}
if (hkEnum) RegCloseKey(hkEnum);
pdl = lpdrvlist;
while (pdl) {
numdrv++;
pdl = pdl->next;
}
if (numdrv) CoInitialize(0); // initialize COM
}
AsioDriverList::~AsioDriverList ()
{
if (numdrv) {
deleteDrvStruct(lpdrvlist);
CoUninitialize();
}
}
LONG AsioDriverList::asioGetNumDev (VOID)
{
return (LONG)numdrv;
}
LONG AsioDriverList::asioOpenDriver (int drvID,LPVOID *asiodrv)
{
LPASIODRVSTRUCT lpdrv = 0;
long rc;
if (!asiodrv) return DRVERR_INVALID_PARAM;
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
if (!lpdrv->asiodrv) {
rc = CoCreateInstance(lpdrv->clsid,0,CLSCTX_INPROC_SERVER,lpdrv->clsid,asiodrv);
if (rc == S_OK) {
lpdrv->asiodrv = *asiodrv;
return 0;
}
// else if (rc == REGDB_E_CLASSNOTREG)
// strcpy (info->messageText, "Driver not registered in the Registration Database!");
}
else rc = DRVERR_DEVICE_ALREADY_OPEN;
}
else rc = DRVERR_DEVICE_NOT_FOUND;
return rc;
}
LONG AsioDriverList::asioCloseDriver (int drvID)
{
LPASIODRVSTRUCT lpdrv = 0;
IASIO *iasio;
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
if (lpdrv->asiodrv) {
iasio = (IASIO *)lpdrv->asiodrv;
iasio->Release();
lpdrv->asiodrv = 0;
}
}
return 0;
}
LONG AsioDriverList::asioGetDriverName (int drvID,char *drvname,int drvnamesize)
{
LPASIODRVSTRUCT lpdrv = 0;
if (!drvname) return DRVERR_INVALID_PARAM;
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
if (strlen(lpdrv->drvname) < (unsigned int)drvnamesize) {
strcpy(drvname,lpdrv->drvname);
}
else {
memcpy(drvname,lpdrv->drvname,drvnamesize-4);
drvname[drvnamesize-4] = '.';
drvname[drvnamesize-3] = '.';
drvname[drvnamesize-2] = '.';
drvname[drvnamesize-1] = 0;
}
return 0;
}
return DRVERR_DEVICE_NOT_FOUND;
}
LONG AsioDriverList::asioGetDriverPath (int drvID,char *dllpath,int dllpathsize)
{
LPASIODRVSTRUCT lpdrv = 0;
if (!dllpath) return DRVERR_INVALID_PARAM;
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
if (strlen(lpdrv->dllpath) < (unsigned int)dllpathsize) {
strcpy(dllpath,lpdrv->dllpath);
return 0;
}
dllpath[0] = 0;
return DRVERR_INVALID_PARAM;
}
return DRVERR_DEVICE_NOT_FOUND;
}
LONG AsioDriverList::asioGetDriverCLSID (int drvID,CLSID *clsid)
{
LPASIODRVSTRUCT lpdrv = 0;
if (!clsid) return DRVERR_INVALID_PARAM;
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
memcpy(clsid,&lpdrv->clsid,sizeof(CLSID));
return 0;
}
return DRVERR_DEVICE_NOT_FOUND;
}

View File

@ -0,0 +1,46 @@
#ifndef __asiolist__
#define __asiolist__
#define DRVERR -5000
#define DRVERR_INVALID_PARAM DRVERR-1
#define DRVERR_DEVICE_ALREADY_OPEN DRVERR-2
#define DRVERR_DEVICE_NOT_FOUND DRVERR-3
#define MAXPATHLEN 512
#define MAXDRVNAMELEN 128
struct asiodrvstruct
{
int drvID;
CLSID clsid;
char dllpath[MAXPATHLEN];
char drvname[MAXDRVNAMELEN];
LPVOID asiodrv;
struct asiodrvstruct *next;
};
typedef struct asiodrvstruct ASIODRVSTRUCT;
typedef ASIODRVSTRUCT *LPASIODRVSTRUCT;
class AsioDriverList {
public:
AsioDriverList();
~AsioDriverList();
LONG asioOpenDriver (int,VOID **);
LONG asioCloseDriver (int);
// nice to have
LONG asioGetNumDev (VOID);
LONG asioGetDriverName (int,char *,int);
LONG asioGetDriverPath (int,char *,int);
LONG asioGetDriverCLSID (int,CLSID *);
// or use directly access
LPASIODRVSTRUCT lpdrvlist;
int numdrv;
};
typedef class AsioDriverList *LPASIODRIVERLIST;
#endif

View File

@ -0,0 +1,82 @@
#ifndef __asiosys__
#define __asiosys__
#ifdef WIN32
#undef MAC
#define PPC 0
#define WINDOWS 1
#define SGI 0
#define SUN 0
#define LINUX 0
#define BEOS 0
#define NATIVE_INT64 0
#define IEEE754_64FLOAT 1
#elif BEOS
#define MAC 0
#define PPC 0
#define WINDOWS 0
#define PC 0
#define SGI 0
#define SUN 0
#define LINUX 0
#define NATIVE_INT64 0
#define IEEE754_64FLOAT 1
#ifndef DEBUG
#define DEBUG 0
#if DEBUG
void DEBUGGERMESSAGE(char *string);
#else
#define DEBUGGERMESSAGE(a)
#endif
#endif
#elif SGI
#define MAC 0
#define PPC 0
#define WINDOWS 0
#define PC 0
#define SUN 0
#define LINUX 0
#define BEOS 0
#define NATIVE_INT64 0
#define IEEE754_64FLOAT 1
#ifndef DEBUG
#define DEBUG 0
#if DEBUG
void DEBUGGERMESSAGE(char *string);
#else
#define DEBUGGERMESSAGE(a)
#endif
#endif
#else // MAC
#define MAC 1
#define PPC 1
#define WINDOWS 0
#define PC 0
#define SGI 0
#define SUN 0
#define LINUX 0
#define BEOS 0
#define NATIVE_INT64 0
#define IEEE754_64FLOAT 1
#ifndef DEBUG
#define DEBUG 0
#if DEBUG
void DEBUGGERMESSAGE(char *string);
#else
#define DEBUGGERMESSAGE(a)
#endif
#endif
#endif
#endif

View File

@ -0,0 +1,202 @@
//==========================================================================;
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved.
//
//--------------------------------------------------------------------------;
// Base class hierachy for creating COM objects, December 1994
#include <windows.h>
#include "wxdebug.h"
#include "combase.h"
#pragma warning( disable : 4514 ) // Disable warnings re unused inline functions
/* Define the static member variable */
LONG CBaseObject::m_cObjects = 0;
/* Constructor */
CBaseObject::CBaseObject(TCHAR *pName)
{
/* Increment the number of active objects */
InterlockedIncrement(&m_cObjects);
#ifdef DEBUG
m_dwCookie = DbgRegisterObjectCreation(pName);
#endif
}
/* Destructor */
CBaseObject::~CBaseObject()
{
/* Decrement the number of objects active */
InterlockedDecrement(&m_cObjects);
#ifdef DEBUG
DbgRegisterObjectDestruction(m_dwCookie);
#endif
}
/* Constructor */
// We know we use "this" in the initialization list, we also know we don't modify *phr.
#pragma warning( disable : 4355 4100 )
CUnknown::CUnknown(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr)
: CBaseObject(pName)
/* Start the object with a reference count of zero - when the */
/* object is queried for it's first interface this may be */
/* incremented depending on whether or not this object is */
/* currently being aggregated upon */
, m_cRef(0)
/* Set our pointer to our IUnknown interface. */
/* If we have an outer, use its, otherwise use ours. */
/* This pointer effectivly points to the owner of */
/* this object and can be accessed by the GetOwner() method. */
, m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
/* Why the double cast? Well, the inner cast is a type-safe cast */
/* to pointer to a type from which we inherit. The second is */
/* type-unsafe but works because INonDelegatingUnknown "behaves */
/* like" IUnknown. (Only the names on the methods change.) */
{
// Everything we need to do has been done in the initializer list
}
#pragma warning( default : 4355 4100 )
/* QueryInterface */
STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
{
CheckPointer(ppv,E_POINTER);
ValidateReadWritePtr(ppv,sizeof(PVOID));
/* We know only about IUnknown */
if (riid == IID_IUnknown) {
GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv);
return NOERROR;
} else {
*ppv = NULL;
return E_NOINTERFACE;
}
}
/* We have to ensure that we DON'T use a max macro, since these will typically */
/* lead to one of the parameters being evaluated twice. Since we are worried */
/* about concurrency, we can't afford to access the m_cRef twice since we can't */
/* afford to run the risk that its value having changed between accesses. */
#ifdef max
#undef max
#endif
template<class T> inline static T max( const T & a, const T & b )
{
return a > b ? a : b;
}
/* AddRef */
STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef()
{
LONG lRef = InterlockedIncrement( &m_cRef );
ASSERT(lRef > 0);
DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"),
m_dwCookie, m_cRef));
return max(ULONG(m_cRef), 1ul);
}
/* Release */
STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease()
{
/* If the reference count drops to zero delete ourselves */
LONG lRef = InterlockedDecrement( &m_cRef );
ASSERT(lRef >= 0);
DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"),
m_dwCookie, m_cRef));
if (lRef == 0) {
// COM rules say we must protect against re-entrancy.
// If we are an aggregator and we hold our own interfaces
// on the aggregatee, the QI for these interfaces will
// addref ourselves. So after doing the QI we must release
// a ref count on ourselves. Then, before releasing the
// private interface, we must addref ourselves. When we do
// this from the destructor here it will result in the ref
// count going to 1 and then back to 0 causing us to
// re-enter the destructor. Hence we add an extra refcount here
// once we know we will delete the object.
// for an example aggregator see filgraph\distrib.cpp.
m_cRef++;
delete this;
return ULONG(0);
} else {
return max(ULONG(m_cRef), 1ul);
}
}
/* Return an interface pointer to a requesting client
performing a thread safe AddRef as necessary */
HRESULT CUnknown::GetInterface(LPUNKNOWN pUnk, void **ppv)
{
CheckPointer(ppv, E_POINTER);
*ppv = pUnk;
pUnk->AddRef();
return NOERROR;
}
/* Compares two interfaces and returns TRUE if they are on the same object */
BOOL IsEqualObject(IUnknown *pFirst, IUnknown *pSecond)
{
/* Different objects can't have the same interface pointer for
any interface
*/
if (pFirst == pSecond) {
return TRUE;
}
/* OK - do it the hard way - check if they have the same
IUnknown pointers - a single object can only have one of these
*/
LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface
LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface
HRESULT hr; // General OLE return code
ASSERT(pFirst);
ASSERT(pSecond);
/* See if the IUnknown pointers match */
hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1);
ASSERT(SUCCEEDED(hr));
ASSERT(pUnknown1);
hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2);
ASSERT(SUCCEEDED(hr));
ASSERT(pUnknown2);
/* Release the extra interfaces we hold */
pUnknown1->Release();
pUnknown2->Release();
return (pUnknown1 == pUnknown2);
}

View File

@ -0,0 +1,282 @@
//==========================================================================;
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved.
//
//--------------------------------------------------------------------------;
// Base class hierachy for creating COM objects, December 1994
/*
a. Derive your COM object from CUnknown
b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT *
and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls
to. The HRESULT * allows error codes to be passed around constructors and
the TCHAR * is a descriptive name that can be printed on the debugger.
It is important that constructors only change the HRESULT * if they have
to set an ERROR code, if it was successful then leave it alone or you may
overwrite an error code from an object previously created.
When you call a constructor the descriptive name should be in static store
as we do not copy the string. To stop large amounts of memory being used
in retail builds by all these static strings use the NAME macro,
CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr);
if (FAILED(hr)) {
return hr;
}
In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class
knows not to do anything with objects that don't have a name.
c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and
TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an
error, or just simply pass it through to the constructor.
The object creation will fail in the class factory if the HRESULT indicates
an error (ie FAILED(HRESULT) == TRUE)
d. Create a FactoryTemplate with your object's class id and CreateInstance
function.
Then (for each interface) either
Multiple inheritance
1. Also derive it from ISomeInterface
2. Include DECLARE_IUNKNOWN in your class definition to declare
implementations of QueryInterface, AddRef and Release that
call the outer unknown
3. Override NonDelegatingQueryInterface to expose ISomeInterface by
code something like
if (riid == IID_ISomeInterface) {
return GetInterface((ISomeInterface *) this, ppv);
} else {
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
}
4. Declare and implement the member functions of ISomeInterface.
or: Nested interfaces
1. Declare a class derived from CUnknown
2. Include DECLARE_IUNKNOWN in your class definition
3. Override NonDelegatingQueryInterface to expose ISomeInterface by
code something like
if (riid == IID_ISomeInterface) {
return GetInterface((ISomeInterface *) this, ppv);
} else {
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
}
4. Implement the member functions of ISomeInterface. Use GetOwner() to
access the COM object class.
And in your COM object class:
5. Make the nested class a friend of the COM object class, and declare
an instance of the nested class as a member of the COM object class.
NOTE that because you must always pass the outer unknown and an hResult
to the CUnknown constructor you cannot use a default constructor, in
other words you will have to make the member variable a pointer to the
class and make a NEW call in your constructor to actually create it.
6. override the NonDelegatingQueryInterface with code like this:
if (riid == IID_ISomeInterface) {
return m_pImplFilter->
NonDelegatingQueryInterface(IID_ISomeInterface, ppv);
} else {
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
}
You can have mixed classes which support some interfaces via multiple
inheritance and some via nested classes
*/
#ifndef __COMBASE__
#define __COMBASE__
/* The DLLENTRY module initialises the module handle on loading */
extern HINSTANCE g_hInst;
/* On DLL load remember which platform we are running on */
extern DWORD g_amPlatform;
extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx
/* Version of IUnknown that is renamed to allow a class to support both
non delegating and delegating IUnknowns in the same COM object */
DECLARE_INTERFACE(INonDelegatingUnknown)
{
STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE;
STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE;
STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE;
};
typedef INonDelegatingUnknown *PNDUNKNOWN;
/* This is the base object class that supports active object counting. As
part of the debug facilities we trace every time a C++ object is created
or destroyed. The name of the object has to be passed up through the class
derivation list during construction as you cannot call virtual functions
in the constructor. The downside of all this is that every single object
constructor has to take an object name parameter that describes it */
class CBaseObject
{
private:
// Disable the copy constructor and assignment by default so you will get
// compiler errors instead of unexpected behaviour if you pass objects
// by value or assign objects.
CBaseObject(const CBaseObject& objectSrc); // no implementation
void operator=(const CBaseObject& objectSrc); // no implementation
private:
static LONG m_cObjects; /* Total number of objects active */
protected:
#ifdef DEBUG
DWORD m_dwCookie; /* Cookie identifying this object */
#endif
public:
/* These increment and decrement the number of active objects */
CBaseObject(TCHAR *pName);
~CBaseObject();
/* Call this to find if there are any CUnknown derived objects active */
static LONG ObjectsActive() {
return m_cObjects;
};
};
/* An object that supports one or more COM interfaces will be based on
this class. It supports counting of total objects for DLLCanUnloadNow
support, and an implementation of the core non delegating IUnknown */
class CUnknown : public INonDelegatingUnknown,
public CBaseObject
{
private:
const LPUNKNOWN m_pUnknown; /* Owner of this object */
protected: /* So we can override NonDelegatingRelease() */
volatile LONG m_cRef; /* Number of reference counts */
public:
CUnknown(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr);
virtual ~CUnknown() {};
/* Return the owner of this object */
LPUNKNOWN GetOwner() const {
return m_pUnknown;
};
/* Called from the class factory to create a new instance, it is
pure virtual so it must be overriden in your derived class */
/* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */
/* Non delegating unknown implementation */
STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **);
STDMETHODIMP_(ULONG) NonDelegatingAddRef();
STDMETHODIMP_(ULONG) NonDelegatingRelease();
/* Return an interface pointer to a requesting client
performing a thread safe AddRef as necessary */
HRESULT GetInterface(LPUNKNOWN pUnk, void **ppv);
};
#if defined(_MSC_VER) && (_MSC_VER<1300)
/* The standard InterlockedXXX functions won't take volatiles */
static inline LONG InterlockedIncrement( volatile LONG * plong )
{ return InterlockedIncrement( const_cast<LONG*>( plong ) ); }
static inline LONG InterlockedDecrement( volatile LONG * plong )
{ return InterlockedDecrement( const_cast<LONG*>( plong ) ); }
static inline LONG InterlockedExchange( volatile LONG * plong, LONG new_value )
{ return InterlockedExchange( const_cast<LONG*>( plong ), new_value ); }
#endif
/* A function that can create a new COM object */
typedef CUnknown *(*LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr);
/* A function (can be NULL) which is called from the DLL entrypoint
routine for each factory template:
bLoading - TRUE on DLL load, FALSE on DLL unload
rclsid - the m_ClsID of the entry
*/
typedef void (*LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid);
/* Create one of these per object class in an array so that
the default class factory code can create new instances */
class CFactoryTemplate {
public:
const WCHAR *m_Name;
const CLSID *m_ClsID;
LPFNNewCOMObject m_lpfnNew;
LPFNInitRoutine m_lpfnInit;
BOOL IsClassID(REFCLSID rclsid) const {
return (IsEqualCLSID(*m_ClsID,rclsid));
};
CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) const {
return m_lpfnNew(pUnk, phr);
};
};
/* You must override the (pure virtual) NonDelegatingQueryInterface to return
interface pointers (using GetInterface) to the interfaces your derived
class supports (the default implementation only supports IUnknown) */
#define DECLARE_IUNKNOWN \
STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { \
return GetOwner()->QueryInterface(riid,ppv); \
}; \
STDMETHODIMP_(ULONG) AddRef() { \
return GetOwner()->AddRef(); \
}; \
STDMETHODIMP_(ULONG) Release() { \
return GetOwner()->Release(); \
};
#endif /* __COMBASE__ */

View File

@ -0,0 +1,14 @@
#include "asiosys.h"
#if DEBUG
#if MAC
#include <TextUtils.h>
void DEBUGGERMESSAGE(char *string)
{
c2pstr(string);
DebugStr((unsigned char *)string);
}
#else
#error debugmessage
#endif
#endif

View File

@ -0,0 +1,323 @@
//==========================================================================;
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved.
//
//--------------------------------------------------------------------------;
//
// classes used to support dll entrypoints for COM objects.
//
// #include "switches.h"
#include <windows.h>
#include "wxdebug.h"
#include "combase.h"
#ifdef DEBUG
#include <tchar.h>
#endif
#include <stdio.h>
extern CFactoryTemplate g_Templates[];
extern int g_cTemplates;
HINSTANCE hinstance = 0;
DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx)
OSVERSIONINFO g_osInfo;
//
// an instance of this is created by the DLLGetClassObject entrypoint
// it uses the CFactoryTemplate object it is given to support the
// IClassFactory interface
class CClassFactory : public IClassFactory
{
private:
const CFactoryTemplate * m_pTemplate;
ULONG m_cRef;
static int m_cLocked;
public:
CClassFactory(const CFactoryTemplate *);
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
STDMETHODIMP_(ULONG)AddRef();
STDMETHODIMP_(ULONG)Release();
// IClassFactory
STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **pv);
STDMETHODIMP LockServer(BOOL fLock);
// allow DLLGetClassObject to know about global server lock status
static BOOL IsLocked() {
return (m_cLocked > 0);
};
};
// process-wide dll locked state
int CClassFactory::m_cLocked = 0;
CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate)
{
m_cRef = 0;
m_pTemplate = pTemplate;
}
STDMETHODIMP CClassFactory::QueryInterface(REFIID riid,void **ppv)
{
CheckPointer(ppv,E_POINTER)
ValidateReadWritePtr(ppv,sizeof(PVOID));
*ppv = NULL;
// any interface on this object is the object pointer.
if ((riid == IID_IUnknown) || (riid == IID_IClassFactory)) {
*ppv = (LPVOID) this;
// AddRef returned interface pointer
((LPUNKNOWN) *ppv)->AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) CClassFactory::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CClassFactory::Release()
{
LONG rc;
if (--m_cRef == 0) {
delete this;
rc = 0;
} else rc = m_cRef;
return rc;
}
STDMETHODIMP CClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,REFIID riid,void **pv)
{
CheckPointer(pv,E_POINTER)
ValidateReadWritePtr(pv,sizeof(void *));
/* Enforce the normal OLE rules regarding interfaces and delegation */
if (pUnkOuter != NULL) {
if (IsEqualIID(riid,IID_IUnknown) == FALSE) {
return ResultFromScode(E_NOINTERFACE);
}
}
/* Create the new object through the derived class's create function */
HRESULT hr = NOERROR;
CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr);
if (pObj == NULL) {
return E_OUTOFMEMORY;
}
/* Delete the object if we got a construction error */
if (FAILED(hr)) {
delete pObj;
return hr;
}
/* Get a reference counted interface on the object */
/* We wrap the non-delegating QI with NDAddRef & NDRelease. */
/* This protects any outer object from being prematurely */
/* released by an inner object that may have to be created */
/* in order to supply the requested interface. */
pObj->NonDelegatingAddRef();
hr = pObj->NonDelegatingQueryInterface(riid, pv);
pObj->NonDelegatingRelease();
/* Note that if NonDelegatingQueryInterface fails, it will */
/* not increment the ref count, so the NonDelegatingRelease */
/* will drop the ref back to zero and the object will "self-*/
/* destruct". Hence we don't need additional tidy-up code */
/* to cope with NonDelegatingQueryInterface failing. */
if (SUCCEEDED(hr)) {
ASSERT(*pv);
}
return hr;
}
STDMETHODIMP CClassFactory::LockServer(BOOL fLock)
{
if (fLock) {
m_cLocked++;
} else {
m_cLocked--;
}
return NOERROR;
}
// --- COM entrypoints -----------------------------------------
// DllRegisterServer
//called by COM to get the class factory object for a given class
STDAPI DllGetClassObject(REFCLSID rClsID,REFIID riid,void **pv)
{
// DebugBreak();
if (!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) {
return E_NOINTERFACE;
}
// traverse the array of templates looking for one with this
// class id
for (int i = 0; i < g_cTemplates; i++) {
const CFactoryTemplate * pT = &g_Templates[i];
if (pT->IsClassID(rClsID)) {
// found a template - make a class factory based on this
// template
*pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT);
if (*pv == NULL) {
return E_OUTOFMEMORY;
}
((LPUNKNOWN)*pv)->AddRef();
return NOERROR;
}
}
return CLASS_E_CLASSNOTAVAILABLE;
}
//
// Call any initialization routines
//
void DllInitClasses(BOOL bLoading)
{
int i;
// DebugBreak();
// traverse the array of templates calling the init routine
// if they have one
for (i = 0; i < g_cTemplates; i++) {
const CFactoryTemplate * pT = &g_Templates[i];
if (pT->m_lpfnInit != NULL) {
(*pT->m_lpfnInit)(bLoading, pT->m_ClsID);
}
}
}
// called by COM to determine if this dll can be unloaded
// return ok unless there are outstanding objects or a lock requested
// by IClassFactory::LockServer
//
// CClassFactory has a static function that can tell us about the locks,
// and CCOMObject has a static function that can tell us about the active
// object count
STDAPI DllCanUnloadNow()
{
// DebugBreak();
DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = %d, Active objects = %d"),
CClassFactory::IsLocked(),
CBaseObject::ObjectsActive()));
if (CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) {
return S_FALSE;
}
else {
return S_OK;
}
}
// --- standard WIN32 entrypoints --------------------------------------
//extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
//BOOL WINAPI DllEntryPoint(HINSTANCE hInstance,ULONG ulReason,LPVOID pv)
//BOOL WINAPI DllMain (HINSTANCE hInstance,ULONG ulReason,LPVOID pv)
BOOL WINAPI DllEntryPoint (HINSTANCE hInstance,ULONG ulReason,LPVOID pv)
{
// DebugBreak();
switch (ulReason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hInstance);
DbgInitialise(hInstance);
{
// The platform identifier is used to work out whether
// full unicode support is available or not. Hence the
// default will be the lowest common denominator - i.e. N/A
g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails
g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo);
if (GetVersionEx(&g_osInfo)) {
g_amPlatform = g_osInfo.dwPlatformId;
}
else {
DbgLog((LOG_ERROR, 1, "Failed to get the OS platform, assuming Win95"));
}
}
hinstance = hInstance;
DllInitClasses(TRUE);
break;
case DLL_PROCESS_DETACH:
DllInitClasses(FALSE);
#ifdef DEBUG
if (CBaseObject::ObjectsActive()) {
DbgSetModuleLevel(LOG_MEMORY, 2);
TCHAR szInfo[512];
extern TCHAR m_ModuleName[]; // Cut down module name
TCHAR FullName[_MAX_PATH]; // Load the full path and module name
TCHAR *pName; // Searches from the end for a backslash
GetModuleFileName(NULL,FullName,_MAX_PATH);
pName = _tcsrchr(FullName,'\\');
if (pName == NULL) {
pName = FullName;
}
else {
pName++;
}
DWORD cch = wsprintf(szInfo, TEXT("Executable: %s Pid %x Tid %x. "),
pName, GetCurrentProcessId(), GetCurrentThreadId());
wsprintf(szInfo+cch, TEXT("Module %s, %d objects left active!"),
m_ModuleName, CBaseObject::ObjectsActive());
DbgAssert(szInfo, TEXT(__FILE__),__LINE__);
// If running remotely wait for the Assert to be acknowledged
// before dumping out the object register
DbgDumpObjectRegister();
}
DbgTerminate();
#endif
break;
}
return TRUE;
}

View File

@ -0,0 +1,38 @@
#ifndef __gInclude__
#define __gInclude__
#if SGI
#undef BEOS
#undef MAC
#undef WINDOWS
//
#define ASIO_BIG_ENDIAN 1
#define ASIO_CPU_MIPS 1
#elif defined WIN32
#undef BEOS
#undef MAC
#undef SGI
#define WINDOWS 1
#define ASIO_LITTLE_ENDIAN 1
#define ASIO_CPU_X86 1
#elif BEOS
#undef MAC
#undef SGI
#undef WINDOWS
#define ASIO_LITTLE_ENDIAN 1
#define ASIO_CPU_X86 1
//
#else
#define MAC 1
#undef BEOS
#undef WINDOWS
#undef SGI
#define ASIO_BIG_ENDIAN 1
#define ASIO_CPU_PPC 1
#endif
// always
#define NATIVE_INT64 0
#define IEEE754_64FLOAT 1
#endif // __gInclude__

View File

@ -0,0 +1,37 @@
#include "asiosys.h"
#include "asio.h"
/* Forward Declarations */
#ifndef __ASIODRIVER_FWD_DEFINED__
#define __ASIODRIVER_FWD_DEFINED__
typedef interface IASIO IASIO;
#endif /* __ASIODRIVER_FWD_DEFINED__ */
interface IASIO : public IUnknown
{
virtual ASIOBool init(void *sysHandle) = 0;
virtual void getDriverName(char *name) = 0;
virtual long getDriverVersion() = 0;
virtual void getErrorMessage(char *string) = 0;
virtual ASIOError start() = 0;
virtual ASIOError stop() = 0;
virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels) = 0;
virtual ASIOError getLatencies(long *inputLatency, long *outputLatency) = 0;
virtual ASIOError getBufferSize(long *minSize, long *maxSize,
long *preferredSize, long *granularity) = 0;
virtual ASIOError canSampleRate(ASIOSampleRate sampleRate) = 0;
virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate) = 0;
virtual ASIOError setSampleRate(ASIOSampleRate sampleRate) = 0;
virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources) = 0;
virtual ASIOError setClockSource(long reference) = 0;
virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0;
virtual ASIOError getChannelInfo(ASIOChannelInfo *info) = 0;
virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels,
long bufferSize, ASIOCallbacks *callbacks) = 0;
virtual ASIOError disposeBuffers() = 0;
virtual ASIOError controlPanel() = 0;
virtual ASIOError future(long selector,void *opt) = 0;
virtual ASIOError outputReady() = 0;
};

View File

@ -0,0 +1,332 @@
#include <windows.h>
#include <stdio.h>
typedef struct keylist
{
HKEY mainKey;
HKEY subKey;
char *keyname;
struct keylist *next;
} KEYLIST, *LPKEYLIST;
#define CLSID_STRING_LEN 100
#define MAX_PATH_LEN 360
#define DEV_ERR_SELFREG -100
#define ERRSREG_MODULE_NOT_FOUND DEV_ERR_SELFREG-1
#define ERRSREG_MODPATH_NOT_FOUND DEV_ERR_SELFREG-2
#define ERRSREG_STRING_FROM_CLSID DEV_ERR_SELFREG-3
#define ERRSREG_CHAR_TO_MULTIBYTE DEV_ERR_SELFREG-4
#define SZREGSTR_DESCRIPTION "Description"
#define SZREGSTR_CLSID "CLSID"
#define SZREGSTR_INPROCSERVER32 "InprocServer32"
#define SZREGSTR_THREADINGMODEL "ThreadingModel"
#define SZREGSTR_SOFTWARE "SOFTWARE"
#define SZREGSTR_ASIO "ASIO"
LONG RegisterAsioDriver (CLSID,char *,char *,char *,char *);
LONG UnregisterAsioDriver (CLSID,char *,char *);
static LONG findRegPath (HKEY,char *);
static LONG createRegPath (HKEY,char *,char *);
static LONG createRegStringValue (HKEY,char *,char *,char *);
static LONG getRegString (HKEY,char *,char *,LPVOID,DWORD);
static LPKEYLIST findAllSubKeys (HKEY,HKEY,DWORD,char *,LPKEYLIST);
static LONG deleteRegPath (HKEY,char *,char *);
static char subkeybuf[MAX_PATH_LEN];
// ------------------------------------------
// Global Functions
// ------------------------------------------
LONG RegisterAsioDriver (CLSID clsid,char *szdllname,char *szregname,char *szasiodesc,char *szthreadmodel)
{
HMODULE hMod;
char szDLLPath[MAX_PATH_LEN];
char szModuleName[MAX_PATH_LEN];
char szregpath[MAX_PATH_LEN];
char szclsid[CLSID_STRING_LEN];
LPOLESTR wszCLSID = NULL;
BOOL newregentry = FALSE;
LONG rc;
hMod = GetModuleHandle(szdllname);
if (!hMod) return ERRSREG_MODULE_NOT_FOUND;
szModuleName[0] = 0;
GetModuleFileName(hMod,szModuleName,MAX_PATH_LEN);
if (!szModuleName[0]) return ERRSREG_MODPATH_NOT_FOUND;
CharLower((LPTSTR)szModuleName);
rc = (LONG)StringFromCLSID(clsid,&wszCLSID);
if (rc != S_OK) return ERRSREG_STRING_FROM_CLSID;
rc = (LONG)WideCharToMultiByte(CP_ACP,0,(LPWSTR)wszCLSID,-1,szclsid,CLSID_STRING_LEN,0,0);
if (!rc) return ERRSREG_CHAR_TO_MULTIBYTE;
sprintf(szregpath,"%s\\%s",SZREGSTR_CLSID,szclsid);
rc = findRegPath(HKEY_CLASSES_ROOT,szregpath);
if (rc) {
sprintf(szregpath,"%s\\%s\\%s",SZREGSTR_CLSID,szclsid,SZREGSTR_INPROCSERVER32);
getRegString (HKEY_CLASSES_ROOT,szregpath,0,(LPVOID)szDLLPath,MAX_PATH_LEN);
CharLower((LPTSTR)szDLLPath);
rc = (LONG)strcmp(szDLLPath,szModuleName);
if (rc) {
// delete old regentry
sprintf(szregpath,"%s",SZREGSTR_CLSID);
deleteRegPath(HKEY_CLASSES_ROOT,szregpath,szclsid);
newregentry = TRUE;
}
}
else newregentry = TRUE;
if (newregentry) {
// HKEY_CLASSES_ROOT\CLSID\{...}
sprintf(szregpath,"%s",SZREGSTR_CLSID);
createRegPath (HKEY_CLASSES_ROOT,szregpath,szclsid);
// HKEY_CLASSES_ROOT\CLSID\{...} -> Description
sprintf(szregpath,"%s\\%s",SZREGSTR_CLSID,szclsid);
createRegStringValue(HKEY_CLASSES_ROOT,szregpath,0,szasiodesc);
// HKEY_CLASSES_ROOT\CLSID\InProcServer32
sprintf(szregpath,"%s\\%s",SZREGSTR_CLSID,szclsid);
createRegPath (HKEY_CLASSES_ROOT,szregpath,SZREGSTR_INPROCSERVER32);
// HKEY_CLASSES_ROOT\CLSID\InProcServer32 -> DLL path
sprintf(szregpath,"%s\\%s\\%s",SZREGSTR_CLSID,szclsid,SZREGSTR_INPROCSERVER32);
createRegStringValue(HKEY_CLASSES_ROOT,szregpath,0,szModuleName);
// HKEY_CLASSES_ROOT\CLSID\InProcServer32 -> ThreadingModel
createRegStringValue(HKEY_CLASSES_ROOT,szregpath,SZREGSTR_THREADINGMODEL,szthreadmodel);
}
// HKEY_LOCAL_MACHINE\SOFTWARE\ASIO
sprintf(szregpath,"%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO);
rc = findRegPath(HKEY_LOCAL_MACHINE,szregpath);
if (rc) {
sprintf(szregpath,"%s\\%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO,szregname);
rc = findRegPath(HKEY_LOCAL_MACHINE,szregpath);
if (rc) {
sprintf(szregpath,"%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO);
deleteRegPath(HKEY_LOCAL_MACHINE,szregpath,szregname);
}
}
else {
// HKEY_LOCAL_MACHINE\SOFTWARE\ASIO
sprintf(szregpath,"%s",SZREGSTR_SOFTWARE);
createRegPath (HKEY_LOCAL_MACHINE,szregpath,SZREGSTR_ASIO);
}
// HKEY_LOCAL_MACHINE\SOFTWARE\ASIO\<szregname>
sprintf(szregpath,"%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO);
createRegPath (HKEY_LOCAL_MACHINE,szregpath,szregname);
// HKEY_LOCAL_MACHINE\SOFTWARE\ASIO\<szregname> -> CLSID
// HKEY_LOCAL_MACHINE\SOFTWARE\ASIO\<szregname> -> Description
sprintf(szregpath,"%s\\%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO,szregname);
createRegStringValue(HKEY_LOCAL_MACHINE,szregpath,SZREGSTR_CLSID,szclsid);
createRegStringValue(HKEY_LOCAL_MACHINE,szregpath,SZREGSTR_DESCRIPTION,szasiodesc);
return 0;
}
LONG UnregisterAsioDriver (CLSID clsid,char *szdllname,char *szregname)
{
LONG rc;
HMODULE hMod;
char szregpath[MAX_PATH_LEN];
char szModuleName[MAX_PATH_LEN];
char szclsid[CLSID_STRING_LEN];
LPOLESTR wszCLSID = NULL;
hMod = GetModuleHandle(szdllname);
if (!hMod) return ERRSREG_MODULE_NOT_FOUND;
szModuleName[0] = 0;
GetModuleFileName(hMod,szModuleName,MAX_PATH_LEN);
if (!szModuleName[0]) return ERRSREG_MODPATH_NOT_FOUND;
CharLower((LPTSTR)szModuleName);
rc = (LONG)StringFromCLSID(clsid,&wszCLSID) ;
if (rc != S_OK) return ERRSREG_STRING_FROM_CLSID;
rc = (LONG)WideCharToMultiByte(CP_ACP,0,(LPWSTR)wszCLSID,-1,szclsid,CLSID_STRING_LEN,0,0);
if (!rc) return ERRSREG_CHAR_TO_MULTIBYTE;
sprintf(szregpath,"%s\\%s",SZREGSTR_CLSID,szclsid);
rc = findRegPath(HKEY_CLASSES_ROOT,szregpath);
if (rc) {
// delete old regentry
sprintf(szregpath,"%s",SZREGSTR_CLSID);
deleteRegPath(HKEY_CLASSES_ROOT,szregpath,szclsid);
}
// HKEY_LOCAL_MACHINE\SOFTWARE\ASIO
sprintf(szregpath,"%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO);
rc = findRegPath(HKEY_LOCAL_MACHINE,szregpath);
if (rc) {
sprintf(szregpath,"%s\\%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO,szregname);
rc = findRegPath(HKEY_LOCAL_MACHINE,szregpath);
if (rc) {
sprintf(szregpath,"%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO);
deleteRegPath(HKEY_LOCAL_MACHINE,szregpath,szregname);
}
}
return 0;
}
// ------------------------------------------
// Local Functions
// ------------------------------------------
static LONG findRegPath (HKEY mainkey,char *szregpath)
{
HKEY hkey;
LONG cr,rc = -1;
if (szregpath) {
if ((cr = RegOpenKey(mainkey,szregpath,&hkey)) == ERROR_SUCCESS) {
RegCloseKey(hkey);
rc = 1;
}
else rc = 0;
}
return rc;
}
static LONG createRegPath (HKEY mainkey,char *szregpath,char *sznewpath)
{
HKEY hkey,hksub;
LONG cr,rc = -1;
char newregpath[MAX_PATH_LEN];
sprintf(newregpath,"%s\\%s",szregpath,sznewpath);
if (!(cr = findRegPath(mainkey,newregpath))) {
if ((cr = RegOpenKey(mainkey,szregpath,&hkey)) == ERROR_SUCCESS) {
if ((cr = RegCreateKey(hkey,sznewpath,&hksub)) == ERROR_SUCCESS) {
RegCloseKey(hksub);
rc = 0;
}
RegCloseKey(hkey);
}
}
else if (cr > 0) rc = 0;
return rc;
}
static LONG createRegStringValue (HKEY mainkey,char *szregpath,char *valname,char *szvalstr)
{
LONG cr,rc = -1;
HKEY hkey;
if (szregpath) {
if ((cr = RegOpenKey(mainkey,szregpath,&hkey)) == ERROR_SUCCESS) {
cr = RegSetValueEx(hkey,(LPCTSTR)valname,0,REG_SZ,(const BYTE *)szvalstr,(DWORD)strlen(szvalstr));
RegCloseKey(hkey);
if (cr == ERROR_SUCCESS) rc = 0;
}
}
return rc;
}
static LONG getRegString (HKEY mainkey,char *szregpath,char *valname,LPVOID pval,DWORD vsize)
{
HKEY hkey;
LONG cr,rc = -1;
DWORD hsize,htype;
if (szregpath) {
if ((cr = RegOpenKey(mainkey,szregpath,&hkey)) == ERROR_SUCCESS) {
cr = RegQueryValueEx(hkey,valname,0,&htype,0,&hsize);
if (cr == ERROR_SUCCESS) {
if (hsize <= vsize) {
cr = RegQueryValueEx(hkey,valname,0,&htype,(LPBYTE)pval,&hsize);
rc = 0;
}
}
RegCloseKey(hkey);
}
}
return rc;
}
static LPKEYLIST findAllSubKeys (HKEY hkey,HKEY hksub,DWORD index,char *keyname,LPKEYLIST kl)
{
HKEY hknew = 0;
char *newkey;
LONG cr;
if (!hksub) {
cr = RegOpenKeyEx(hkey,(LPCTSTR)keyname,0,KEY_ALL_ACCESS,&hknew);
if (cr != ERROR_SUCCESS) return kl;
}
else hknew = hksub;
cr = RegEnumKey(hknew,index,(LPTSTR)subkeybuf,MAX_PATH_LEN);
if (cr == ERROR_SUCCESS) {
newkey = new char[strlen(subkeybuf)+1];
strcpy(newkey,subkeybuf);
kl = findAllSubKeys(hknew,0,0,newkey,kl);
kl = findAllSubKeys(hkey,hknew,index+1,keyname,kl);
return kl;
}
if (!kl->next) {
kl->next = new KEYLIST[1];
kl = kl->next;
kl->mainKey = hkey;
kl->subKey = hknew;
kl->keyname = keyname;
kl->next = 0;
}
return kl;
}
static LONG deleteRegPath (HKEY mainkey,char *szregpath,char *szdelpath)
{
HKEY hkey;
LONG cr,rc = -1;
KEYLIST klist;
LPKEYLIST pkl,k;
char *keyname = 0;
if ((cr = RegOpenKey(mainkey,szregpath,&hkey)) == ERROR_SUCCESS) {
keyname = new char[strlen(szdelpath)+1];
if (!keyname) {
RegCloseKey(hkey);
return rc;
}
strcpy(keyname,szdelpath);
klist.next = 0;
findAllSubKeys(hkey,0,0,keyname,&klist);
if (klist.next) {
pkl = klist.next;
while (pkl) {
RegCloseKey(pkl->subKey);
cr = RegDeleteKey(pkl->mainKey,pkl->keyname);
delete pkl->keyname;
k = pkl;
pkl = pkl->next;
delete k;
}
rc = 0;
}
RegCloseKey(hkey);
}
return rc;
}

View File

@ -0,0 +1,326 @@
//==========================================================================;
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved.
//
//--------------------------------------------------------------------------;
// Debugging facilities, January 1995
#ifndef __WXDEBUG__
#define __WXDEBUG__
// Avoid conflict with MFC
#undef ASSERT
// This library provides fairly straight forward debugging functionality, this
// is split into two main sections. The first is assertion handling, there are
// three types of assertions provided here. The most commonly used one is the
// ASSERT(condition) macro which will pop up a message box including the file
// and line number if the condition evaluates to FALSE. Then there is the
// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will
// still be executed in NON debug builds. The final type of assertion is the
// KASSERT macro which is more suitable for pure (perhaps kernel) filters as
// the condition is printed onto the debugger rather than in a message box.
//
// The other part of the debug module facilties is general purpose logging.
// This is accessed by calling DbgLog(). The function takes a type and level
// field which define the type of informational string you are presenting and
// it's relative importance. The type field can be a combination (one or more)
// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level
// is a DWORD value where zero defines highest important. Use of zero as the
// debug logging level is to be encouraged ONLY for major errors or events as
// they will ALWAYS be displayed on the debugger. Other debug output has it's
// level matched against the current debug output level stored in the registry
// for this module and if less than the current setting it will be displayed.
//
// Each module or executable has it's own debug output level for each of the
// five types. These are read in when the DbgInitialise function is called
// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL
// is loaded, executables must call it explicitely with the module instance
// handle given to them through the WINMAIN entry point. An executable must
// also call DbgTerminate when they have finished to clean up the resources
// the debug library uses, once again this is done automatically for DLLs
// These are the five different categories of logging information
enum { LOG_TIMING = 0x01, // Timing and performance measurements
LOG_TRACE = 0x02, // General step point call tracing
LOG_MEMORY = 0x04, // Memory and object allocation/destruction
LOG_LOCKING = 0x08, // Locking/unlocking of critical sections
LOG_ERROR = 0x10 }; // Debug error notification
enum { CDISP_HEX = 0x01,
CDISP_DEC = 0x02};
// For each object created derived from CBaseObject (in debug builds) we
// create a descriptor that holds it's name (statically allocated memory)
// and a cookie we assign it. We keep a list of all the active objects
// we have registered so that we can dump a list of remaining objects
typedef struct tag_ObjectDesc {
TCHAR *m_pName;
DWORD m_dwCookie;
tag_ObjectDesc *m_pNext;
} ObjectDesc;
#define DLLIMPORT __declspec(dllimport)
#define DLLEXPORT __declspec(dllexport)
#ifdef DEBUG
#define NAME(x) TEXT(x)
// These are used internally by the debug library (PRIVATE)
void DbgInitKeyLevels(HKEY hKey);
void DbgInitGlobalSettings();
void DbgInitModuleSettings();
void DbgInitModuleName();
DWORD DbgRegisterObjectCreation(TCHAR *pObjectName);
BOOL DbgRegisterObjectDestruction(DWORD dwCookie);
// These are the PUBLIC entry points
BOOL DbgCheckModuleLevel(DWORD Type,DWORD Level);
void DbgSetModuleLevel(DWORD Type,DWORD Level);
// Initialise the library with the module handle
void DbgInitialise(HINSTANCE hInst);
void DbgTerminate();
void DbgDumpObjectRegister();
// Display error and logging to the user
void DbgAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine);
void DbgBreakPoint(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine);
void DbgKernelAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine);
void DbgLogInfo(DWORD Type,DWORD Level,const TCHAR *pFormat,...);
void DbgOutString(LPCTSTR psz);
// Debug infinite wait stuff
DWORD DbgWaitForSingleObject(HANDLE h);
DWORD DbgWaitForMultipleObjects(DWORD nCount,
CONST HANDLE *lpHandles,
BOOL bWaitAll);
void DbgSetWaitTimeout(DWORD dwTimeout);
#ifdef __strmif_h__
void DisplayType(LPSTR label, const AM_MEDIA_TYPE *pmtIn);
#endif
#define KASSERT(_x_) if (!(_x_)) \
DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__)
// Break on the debugger without putting up a message box
// message goes to debugger instead
#define KDbgBreak(_x_) \
DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__)
#define ASSERT(_x_) if (!(_x_)) \
DbgAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__)
// Put up a message box informing the user of a halt
// condition in the program
#define DbgBreak(_x_) \
DbgBreakPoint(TEXT(#_x_),TEXT(__FILE__),__LINE__)
#define EXECUTE_ASSERT(_x_) ASSERT(_x_)
#define DbgLog(_x_) DbgLogInfo _x_
// MFC style trace macros
#define NOTE(_x_) DbgLog((LOG_TRACE,5,TEXT(_x_)));
#define NOTE1(_x_,a) DbgLog((LOG_TRACE,5,TEXT(_x_),a));
#define NOTE2(_x_,a,b) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b));
#define NOTE3(_x_,a,b,c) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c));
#define NOTE4(_x_,a,b,c,d) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d));
#define NOTE5(_x_,a,b,c,d,e) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d,e));
#else
// Retail builds make public debug functions inert - WARNING the source
// files do not define or build any of the entry points in debug builds
// (public entry points compile to nothing) so if you go trying to call
// any of the private entry points in your source they won't compile
#define NAME(_x_) NULL
#define DbgInitialise(hInst)
#define DbgTerminate()
#define DbgLog(_x_)
#define DbgOutString(psz)
#define DbgRegisterObjectCreation(pObjectName)
#define DbgRegisterObjectDestruction(dwCookie)
#define DbgDumpObjectRegister()
#define DbgCheckModuleLevel(Type,Level)
#define DbgSetModuleLevel(Type,Level)
#define DbgWaitForSingleObject(h) WaitForSingleObject(h, INFINITE)
#define DbgWaitForMultipleObjects(nCount, lpHandles, bWaitAll) \
WaitForMultipleObjects(nCount, lpHandles, bWaitAll, INFINITE)
#define DbgSetWaitTimeout(dwTimeout)
#define KDbgBreak(_x_)
#define DbgBreak(_x_)
#define KASSERT(_x_)
#define ASSERT(_x_)
#define EXECUTE_ASSERT(_x_) _x_
// MFC style trace macros
#define NOTE(_x_)
#define NOTE1(_x_,a)
#define NOTE2(_x_,a,b)
#define NOTE3(_x_,a,b,c)
#define NOTE4(_x_,a,b,c,d)
#define NOTE5(_x_,a,b,c,d,e)
#define DisplayType(label, pmtIn)
#endif
// Checks a pointer which should be non NULL - can be used as follows.
#define CheckPointer(p,ret) {if((p)==NULL) return (ret);}
// HRESULT Foo(VOID *pBar)
// {
// CheckPointer(pBar,E_INVALIDARG)
// }
//
// Or if the function returns a boolean
//
// BOOL Foo(VOID *pBar)
// {
// CheckPointer(pBar,FALSE)
// }
// These validate pointers when symbol VFWROBUST is defined
// This will normally be defined in debug not retail builds
#ifdef DEBUG
#define VFWROBUST
#endif
#ifdef VFWROBUST
#define ValidateReadPtr(p,cb) \
{if(IsBadReadPtr((PVOID)p,cb) == TRUE) \
DbgBreak("Invalid read pointer");}
#define ValidateWritePtr(p,cb) \
{if(IsBadWritePtr((PVOID)p,cb) == TRUE) \
DbgBreak("Invalid write pointer");}
#define ValidateReadWritePtr(p,cb) \
{ValidateReadPtr(p,cb) ValidateWritePtr(p,cb)}
#define ValidateStringPtr(p) \
{if(IsBadStringPtr((LPCTSTR)p,INFINITE) == TRUE) \
DbgBreak("Invalid string pointer");}
#define ValidateStringPtrA(p) \
{if(IsBadStringPtrA((LPCSTR)p,INFINITE) == TRUE) \
DbgBreak("Invalid ANSII string pointer");}
#define ValidateStringPtrW(p) \
{if(IsBadStringPtrW((LPCWSTR)p,INFINITE) == TRUE) \
DbgBreak("Invalid UNICODE string pointer");}
#else
#define ValidateReadPtr(p,cb)
#define ValidateWritePtr(p,cb)
#define ValidateReadWritePtr(p,cb)
#define ValidateStringPtr(p)
#define ValidateStringPtrA(p)
#define ValidateStringPtrW(p)
#endif
#ifdef _OBJBASE_H_
// Outputting GUID names. If you want to include the name
// associated with a GUID (eg CLSID_...) then
//
// GuidNames[yourGUID]
//
// Returns the name defined in uuids.h as a string
typedef struct {
TCHAR *szName;
GUID guid;
} GUID_STRING_ENTRY;
class CGuidNameList {
public:
TCHAR *operator [] (const GUID& guid);
};
extern CGuidNameList GuidNames;
#endif
// REMIND macro - generates warning as reminder to complete coding
// (eg) usage:
//
// #pragma message (REMIND("Add automation support"))
#define QUOTE(x) #x
#define QQUOTE(y) QUOTE(y)
#define REMIND(str) __FILE__ "(" QQUOTE(__LINE__) ") : " str
// Hack to display objects in a useful format
//
// eg If you want to display a LONGLONG ll in a debug string do (eg)
//
// DbgLog((LOG_TRACE, n, TEXT("Value is %s"), (LPCTSTR)CDisp(ll, CDISP_HEX)));
class CDispBasic
{
public:
CDispBasic() { m_pString = m_String; };
~CDispBasic();
protected:
PTCHAR m_pString; // normally points to m_String... unless too much data
TCHAR m_String[50];
};
class CDisp : public CDispBasic
{
public:
CDisp(LONGLONG ll, int Format = CDISP_HEX); // Display a LONGLONG in CDISP_HEX or CDISP_DEC form
CDisp(REFCLSID clsid); // Display a GUID
CDisp(double d); // Display a floating point number
#ifdef __strmif_h__
#ifdef __STREAMS__
CDisp(CRefTime t); // Display a Reference Time
#endif
CDisp(IPin *pPin); // Display a pin as {filter clsid}(pin name)
#endif // __strmif_h__
~CDisp();
// Implement cast to (LPCTSTR) as parameter to logger
operator LPCTSTR()
{
return (LPCTSTR)m_pString;
};
};
#endif // __WXDEBUG__

685
plugins/spu2ghz/asioout.cpp Normal file
View File

@ -0,0 +1,685 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#include "spu2.h"
#include <stdio.h>
#include <string.h>
#include "asio/asiosys.h"
#include "asio/asio.h"
#include "asio/asioDrivers.h"
#include "asio/ASIOConvertSamples.h"
extern double pow_2_31;
class ASIOOutModule: public SndOutModule
{
private:
bool showBufferInfo;
bool bufferInfoReady;
char *bufferSampleType;
int OutputSamples;
#ifndef __WIN64__
#define BufferSize (CurBufferSize<<1)
#define BufferSizeBytes (BufferSize<<2)
s32* asio_lbuffer;
AsioDrivers *asioDrivers;
SndBuffer *buff;
enum
{
kMaxInputChannels = 0,
kMaxOutputChannels = 2
};
// internal data storage
typedef struct DriverInfo
{
// ASIOInit()
ASIODriverInfo driverInfo;
// ASIOGetChannels()
long inputChannels;
long outputChannels;
// ASIOGeasio_tbufferSize()
long minSize;
long maxSize;
long preferredSize;
long granularity;
// ASIOGetSampleRate()
ASIOSampleRate sampleRate;
// ASIOOutputReady()
bool postOutput;
// ASIOGetLatencies ()
long inputLatency;
long outputLatency;
// ASIOCreateBuffers ()
long inputBuffers; // becomes number of actual created input buffers
long outputBuffers; // becomes number of actual created output buffers
ASIOBufferInfo bufferInfos[kMaxInputChannels + kMaxOutputChannels]; // buffer info's
// ASIOGetChannelInfo()
ASIOChannelInfo channelInfos[kMaxInputChannels + kMaxOutputChannels]; // channel info's
// The above two arrays share the same indexing, as the data in them are linked together
// Information from ASIOGetSamplePosition()
// data is converted to double floats for easier use, however 64 bit integer can be used, too
double nanoSeconds;
double samples;
double tcSamples; // time code samples
// bufferSwitchTimeInfo()
ASIOTime tInfo; // time info state
unsigned long sysRefTime; // system reference time, when bufferSwitch() was called
// Signal the end of processing in this example
bool stopped;
} DriverInfo;
DriverInfo asioDriverInfo;
ASIOCallbacks asioCallbacks;
//----------------------------------------------------------------------------------
long init_asio_static_data ()//DriverInfo *asioDriverInfo)
{ // collect the informational data of the driver
// get the number of available channels
if(ASIOGetChannels(&asioDriverInfo.inputChannels, &asioDriverInfo.outputChannels) == ASE_OK)
{
// get the usable buffer sizes
if(ASIOGetBufferSize(&asioDriverInfo.minSize, &asioDriverInfo.maxSize, &asioDriverInfo.preferredSize, &asioDriverInfo.granularity) == ASE_OK)
{
if(ASIOCanSampleRate(SampleRate) != ASE_OK)
{
ConLog(" * SPU2: ERROR: Sample rate not supported!\n");
return -7;
}
if(ASIOSetSampleRate(SampleRate) == ASE_OK)
{
if(ASIOGetSampleRate(&asioDriverInfo.sampleRate) != ASE_OK)
return -6;
if(asioDriverInfo.sampleRate != SampleRate)
{
ConLog(" * SPU2: ERROR: Sample rate couldn't be set to the specified value!\n");
return -8;
}
}
else
return -5;
}
// check wether the driver requires the ASIOOutputReady() optimization
// (can be used by the driver to reduce output latency by one block)
if(ASIOOutputReady() == ASE_OK)
asioDriverInfo.postOutput = true;
else
asioDriverInfo.postOutput = false;
return 0;
}
return -1;
}
//----------------------------------------------------------------------------------
// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
#if NATIVE_INT64
#define ASIO64toDouble(a) (a)
#else
#define ASIO64toDouble(a) ((a).lo + (a).hi * pow_2_31*2)
#endif
static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow)
{
return ASIOMod.TbufferSwitchTimeInfo(timeInfo,index,processNow);
}
ASIOTime *TbufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow)
{ // the actual processing callback.
// Beware that this is normally in a seperate thread, hence be sure that you take care
// about thread synchronization. This is omitted here for simplicity.
static int processedSamples = 0;
// buffer size in samples
long buffSize = asioDriverInfo.preferredSize;
static long oldBuffSize=0;
ASIOConvertSamples converter;
#define DBL(t) ((t*)(asioDriverInfo.bufferInfos[0].buffers[index]))
#define DBR(t) ((t*)(asioDriverInfo.bufferInfos[1].buffers[index]))
int BLen=BufferSize*CurBufferCount;
int ssize=2;
if(showBufferInfo)
{
switch (asioDriverInfo.channelInfos[0].type)
{
case ASIOSTInt16LSB:
bufferSampleType = "16bit Integer (LSB)";
break;
case ASIOSTInt24LSB: // used for 20 bits as well
bufferSampleType = "24bit Integer (LSB)";
break;
case ASIOSTInt32LSB:
bufferSampleType = "32bit Integer (LSB)";
break;
case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
bufferSampleType = "32bit Integer with 16bit alignment (LSB)";
break;
case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
bufferSampleType = "32bit Integer with 18bit alignment (LSB)";
break;
case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
bufferSampleType = "32bit Integer with 20bit alignment (LSB)";
break;
case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
bufferSampleType = "32bit Integer with 24bit alignment (LSB)";
break;
case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
bufferSampleType = "32bit Float (LSB)";
break;
case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
bufferSampleType = "64bit Float (LSB)";
break;
case ASIOSTInt16MSB:
bufferSampleType = "16bit Integer (MSB)";
break;
case ASIOSTInt24MSB: // used for 20 bits as well
bufferSampleType = "24bit Integer (MSB)";
break;
case ASIOSTInt32MSB:
bufferSampleType = "32bit Integer (MSB)";
break;
case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
bufferSampleType = "32bit Integer with 16bit alignment (MSB)";
break;
case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
bufferSampleType = "32bit Integer with 18bit alignment (MSB)";
break;
case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
bufferSampleType = "32bit Integer with 20bit alignment (MSB)";
break;
case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
bufferSampleType = "32bit Integer with 24bit alignment (MSB)";
break;
case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
bufferSampleType = "32bit Float (MSB)";
break;
case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
bufferSampleType = "64bit Float (MSB)";
break;
}
bufferInfoReady=true;
}
buff->ReadSamples(asio_lbuffer,buffSize<<1);
s32 asio_read_num = 0;
// perform the processing
switch (asioDriverInfo.channelInfos[0].type)
{
case ASIOSTInt16LSB:
for(int i=0;i<buffSize;i++)
{
DBL(__int16)[i]=asio_lbuffer[asio_read_num++]>>8;
DBR(__int16)[i]=asio_lbuffer[asio_read_num++]>>8;
}
ssize=2;
break;
case ASIOSTInt24LSB: // used for 20 bits as well
for(int i=0;i<buffSize;i++)
{
DBL(__int32)[i]=(s32)(asio_lbuffer[asio_read_num++])<<8;
DBR(__int32)[i]=(s32)(asio_lbuffer[asio_read_num++])<<8;
}
converter.int32to24inPlace(DBL(__int16),buffSize);
converter.int32to24inPlace(DBR(__int16),buffSize);
ssize=3;
break;
case ASIOSTInt32LSB:
case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
for(int i=0;i<buffSize;i++)
{
DBL(__int32)[i]=(s32)(asio_lbuffer[asio_read_num++])<<8;
DBR(__int32)[i]=(s32)(asio_lbuffer[asio_read_num++])<<8;
}
ssize=4;
break;
case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
for(int i=0;i<buffSize;i++)
{
DBL(float)[i]=asio_lbuffer[asio_read_num++]/16777216.0f;
DBR(float)[i]=asio_lbuffer[asio_read_num++]/16777216.0f;
}
ssize=4;
break;
case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
for(int i=0;i<buffSize;i++)
{
DBL(double)[i]=asio_lbuffer[asio_read_num++]/16777216.0;
DBR(double)[i]=asio_lbuffer[asio_read_num++]/16777216.0;
}
ssize=8;
break;
case ASIOSTInt16MSB:
for(int i=0;i<buffSize;i++)
{
DBL(__int16)[i]=asio_lbuffer[asio_read_num++]>>8;
DBR(__int16)[i]=asio_lbuffer[asio_read_num++]>>8;
}
converter.reverseEndian(DBL(__int16),2,buffSize);
converter.reverseEndian(DBR(__int16),2,buffSize);
ssize=2;
break;
case ASIOSTInt24MSB: // used for 20 bits as well
for(int i=0;i<buffSize;i++)
{
DBL(__int32)[i]=asio_lbuffer[asio_read_num++]<<8;
DBR(__int32)[i]=asio_lbuffer[asio_read_num++]<<8;
}
converter.int32to24inPlace(DBL(__int16),buffSize);
converter.int32to24inPlace(DBR(__int16),buffSize);
converter.reverseEndian(DBL(__int16),3,buffSize);
converter.reverseEndian(DBR(__int16),3,buffSize);
ssize=3;
break;
case ASIOSTInt32MSB:
case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
for(int i=0;i<buffSize;i++)
{
DBL(__int32)[i]=(s32)(asio_lbuffer[asio_read_num++])<<8;
DBR(__int32)[i]=(s32)(asio_lbuffer[asio_read_num++])<<8;
}
converter.reverseEndian(DBL(__int16),4,buffSize);
converter.reverseEndian(DBR(__int16),4,buffSize);
ssize=4;
break;
case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
for(int i=0;i<buffSize;i++)
{
DBL(float)[i]=asio_lbuffer[asio_read_num++]/16777216.0f;
DBR(float)[i]=asio_lbuffer[asio_read_num++]/16777216.0f;
}
converter.reverseEndian(DBL(__int16),4,buffSize);
converter.reverseEndian(DBR(__int16),4,buffSize);
ssize=4;
break;
case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
for(int i=0;i<buffSize;i++)
{
DBL(double)[i]=asio_lbuffer[asio_read_num++]/16777216.0;
DBR(double)[i]=asio_lbuffer[asio_read_num++]/16777216.0;
}
converter.reverseEndian(DBL(__int16),8,buffSize);
converter.reverseEndian(DBR(__int16),8,buffSize);
ssize=8;
break;
}
// finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place
if (asioDriverInfo.postOutput)
ASIOOutputReady();
OutputSamples+=buffSize;
return 0L;
}
//----------------------------------------------------------------------------------
static void bufferSwitch(long index, ASIOBool processNow)
{ // the actual processing callback.
// Beware that this is normally in a seperate thread, hence be sure that you take care
// about thread synchronization. This is omitted here for simplicity.
// as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs to be created
// though it will only set the timeInfo.samplePosition and timeInfo.systemTime fields and the according flags
ASIOTime timeInfo;
memset (&timeInfo, 0, sizeof (timeInfo));
// get the time stamp of the buffer, not necessary if no
// synchronization to other media is required
//if(ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
// timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
bufferSwitchTimeInfo (&timeInfo, index, processNow);
}
//----------------------------------------------------------------------------------
static void sampleRateChanged(ASIOSampleRate sRate)
{
// do whatever you need to do if the sample rate changed
// usually this only happens during external sync.
// Audio processing is not stopped by the driver, actual sample rate
// might not have even changed, maybe only the sample rate status of an
// AES/EBU or S/PDIF digital input at the audio device.
// You might have to update time/sample related conversion routines, etc.
ConLog(" * SPU2: ASIO sample rate changed to %f\n",sRate);
}
//----------------------------------------------------------------------------------
static long asioMessages(long selector, long value, void* message, double* opt)
{
return ASIOMod.TasioMessages(selector,value,message,opt);
}
long TasioMessages(long selector, long value, void* message, double* opt)
{
// currently the parameters "value", "message" and "opt" are not used.
long ret = 0;
switch(selector)
{
case kAsioSelectorSupported:
if(value == kAsioResetRequest
|| value == kAsioEngineVersion
|| value == kAsioResyncRequest
|| value == kAsioLatenciesChanged
// the following three were added for ASIO 2.0, you don't necessarily have to support them
|| value == kAsioSupportsTimeInfo
|| value == kAsioSupportsTimeCode
|| value == kAsioSupportsInputMonitor)
ret = 1L;
break;
case kAsioResetRequest:
// defer the task and perform the reset of the driver during the next "safe" situation
// You cannot reset the driver right now, as this code is called from the driver.
// Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction
// Afterwards you initialize the driver again.
asioDriverInfo.stopped; // In this sample the processing will just stop
ret = 1L;
break;
case kAsioResyncRequest:
// This informs the application, that the driver encountered some non fatal data loss.
// It is used for synchronization purposes of different media.
// Added mainly to work around the Win16Mutex problems in Windows 95/98 with the
// Windows Multimedia system, which could loose data because the Mutex was hold too long
// by another thread.
// However a driver can issue it in other situations, too.
ret = 1L;
break;
case kAsioLatenciesChanged:
// This will inform the host application that the drivers were latencies changed.
// Beware, it this does not mean that the buffer sizes have changed!
// You might need to update internal delay data.
ret = 1L;
break;
case kAsioEngineVersion:
// return the supported ASIO version of the host application
// If a host applications does not implement this selector, ASIO 1.0 is assumed
// by the driver
ret = 2L;
break;
case kAsioSupportsTimeInfo:
// informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
// is supported.
// For compatibility with ASIO 1.0 drivers the host application should always support
// the "old" bufferSwitch method, too.
ret = 1;
break;
case kAsioSupportsTimeCode:
// informs the driver wether application is interested in time code info.
// If an application does not need to know about time code, the driver has less work
// to do.
ret = 0;
break;
}
return ret;
}
//----------------------------------------------------------------------------------
ASIOError create_asio_buffers () //DriverInfo *asioDriverInfo)
{ // create buffers for all inputs and outputs of the card with the
// preferredSize from ASIOGeasio_tbufferSize() as buffer size
long i;
ASIOError result;
// fill the bufferInfos from the start without a gap
ASIOBufferInfo *info = asioDriverInfo.bufferInfos;
// prepare inputs (Though this is not necessaily required, no opened inputs will work, too
if (asioDriverInfo.inputChannels > kMaxInputChannels)
asioDriverInfo.inputBuffers = kMaxInputChannels;
else
asioDriverInfo.inputBuffers = asioDriverInfo.inputChannels;
for(i = 0; i < asioDriverInfo.inputBuffers; i++, info++)
{
info->isInput = ASIOTrue;
info->channelNum = i;
info->buffers[0] = info->buffers[1] = 0;
}
// prepare outputs
if (asioDriverInfo.outputChannels > kMaxOutputChannels)
asioDriverInfo.outputBuffers = kMaxOutputChannels;
else
asioDriverInfo.outputBuffers = asioDriverInfo.outputChannels;
for(i = 0; i < asioDriverInfo.outputBuffers; i++, info++)
{
info->isInput = ASIOFalse;
info->channelNum = i;
info->buffers[0] = info->buffers[1] = 0;
}
// create and activate buffers
result = ASIOCreateBuffers(asioDriverInfo.bufferInfos,
asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers,
asioDriverInfo.preferredSize, &asioCallbacks);
if (result == ASE_OK)
{
// now get all the buffer details, sample word length, name, word clock group and activation
for (i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++)
{
asioDriverInfo.channelInfos[i].channel = asioDriverInfo.bufferInfos[i].channelNum;
asioDriverInfo.channelInfos[i].isInput = asioDriverInfo.bufferInfos[i].isInput;
result = ASIOGetChannelInfo(&asioDriverInfo.channelInfos[i]);
if (result != ASE_OK)
break;
}
if (result == ASE_OK)
{
// get the input and output latencies
// Latencies often are only valid after ASIOCreateBuffers()
// (input latency is the age of the first sample in the currently returned audio block)
// (output latency is the time the first sample in the currently returned audio block requires to get to the output)
result = ASIOGetLatencies(&asioDriverInfo.inputLatency, &asioDriverInfo.outputLatency);
if (result == ASE_OK)
ConLog(" * SPU2: ASIOGetLatencies (input: %d, output: %d);\n", asioDriverInfo.inputLatency, asioDriverInfo.outputLatency);
}
}
return result;
}
unsigned long get_sys_reference_time()
{ // get the system reference time
#if WINDOWS
return timeGetTime();
#elif MAC
static const double twoRaisedTo32 = 4294967296.;
UnsignedWide ys;
Microseconds(&ys);
double r = ((double)ys.hi * twoRaisedTo32 + (double)ys.lo);
return (unsigned long)(r / 1000.);
#endif
}
#endif
public:
bool handling_exception;
LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
static LONG WINAPI UEH(struct _EXCEPTION_POINTERS* ExceptionInfo)
{
ASIOMod.handling_exception=true;
ConLog(" * SPU2: Exception catched. Closing ASIO...\n");
ASIOMod.Close();
ASIOMod.handling_exception=false;
return EXCEPTION_CONTINUE_SEARCH;
}
s32 Init(SndBuffer *sb)
{
buff=sb;
oldFilter = SetUnhandledExceptionFilter(UEH);
#ifndef __WIN64__
char driverNameSpace[100*40];
char* driverNames[100];
asio_lbuffer= new s32[BufferSize];
for(int i=0;i<100;i++)
driverNames[i]=driverNameSpace+(i*40);
asioDrivers=new AsioDrivers();
long driverMax=asioDrivers->getDriverNames(driverNames,100);
long selected=-1;
ConLog(" * SPU2: ASIO Output Module: There are %u ASIO drivers available:\n",driverMax);
for(int i=0;i<driverMax;i++)
{
ConLog(" *** %u - %s\n",i+1,driverNames[i]);
if(stricmp(driverNames[i],AsioDriver)==0)
{
selected=i+1;
break;
}
}
if(strlen(AsioDriver)==0)
selected=-2;
if(selected==-1)
ConLog(" * SPU2: ASIO Output Module: Driver not found. Using Driver: '%s'.\n",driverNames[0]);
else if(selected==-2)
ConLog(" * SPU2: ASIO Output Module: Driver not specified. Using Driver: '%s'.\n",driverNames[0]);
else
ConLog(" * SPU2: ASIO Output Module: Using driver '%s'.\n",driverNames[selected-1]);
if(selected<1) selected=1;
if(!(asioDrivers->loadDriver(driverNames[selected-1])))
{
return -1;
}
// initialize the driver
if (ASIOInit (&asioDriverInfo.driverInfo) != ASE_OK)
{
asioDrivers->removeCurrentDriver();
return -1;
}
if (init_asio_static_data () != 0)
{
ASIOExit();
asioDrivers->removeCurrentDriver();
return -1;
}
// ASIOControlPanel(); you might want to check wether the ASIOControlPanel() can open
// set up the asioCallback structure and create the ASIO data buffer
asioCallbacks.bufferSwitch = &bufferSwitch;
asioCallbacks.sampleRateDidChange = &sampleRateChanged;
asioCallbacks.asioMessage = &asioMessages;
asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo;
if (create_asio_buffers () != ASE_OK)
{
ASIOExit();
asioDrivers->removeCurrentDriver();
return -1;
}
if (ASIOStart() != ASE_OK)
{
ASIODisposeBuffers();
ASIOExit();
asioDrivers->removeCurrentDriver();
return -1;
}
return 0;
#else
return -1;
#endif
}
void Close()
{
if(!handling_exception)
SetUnhandledExceptionFilter(oldFilter);
#ifndef __WIN64__
ASIOStop();
Sleep(1);
ASIODisposeBuffers();
ASIOExit();
if(asioDrivers) asioDrivers->removeCurrentDriver();
delete asio_lbuffer;
#endif
}
virtual void Configure(HWND parent)
{
}
virtual bool Is51Out() { return false; }
s32 Test()
{
#ifndef __WIN64__
if(asioDrivers->asioGetNumDev()>0)
return 0;
#endif
return -1;
}
} ASIOMod;
SndOutModule *ASIOOut=&ASIOMod;

580
plugins/spu2ghz/config.cpp Normal file
View File

@ -0,0 +1,580 @@
///GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#include "spu2.h"
#include "dialogs.h"
// Config Vars
// DEBUG
bool DebugEnabled=false;
bool MsgToConsole=false;
bool MsgKeyOnOff=false;
bool MsgVoiceOff=false;
bool MsgDMA=false;
bool MsgAutoDMA=false;
bool AccessLog=false;
bool DMALog=false;
bool WaveLog=false;
bool CoresDump=false;
bool MemDump=false;
bool RegDump=false;
char AccessLogFileName[255];
char WaveLogFileName[255];
char DMA4LogFileName[255];
char DMA7LogFileName[255];
char CoresDumpFileName[255];
char MemDumpFileName[255];
char RegDumpFileName[255];
int WaveDumpFormat;
int AutoDMAPlayRate[2]={0,0};
// MIXING
int Interpolation=1;
/* values:
0: no interpolation (use nearest)
1. linear interpolation
2. cubic interpolation
*/
// EFFECTS
bool EffectsEnabled=false;
// OUTPUT
int SampleRate=48000;
int CurBufferSize=1024;
int MaxBufferCount=8;
int CurBufferCount=MaxBufferCount;
int OutputModule=OUTPUT_DSOUND;
int VolumeMultiplier=1;
int VolumeDivisor=1;
int LimitMode=0;
/* values:
0. No limiter
1. Soft limiter -- less cpu-intensive, but can cause problems
2. Hard limiter -- more cpu-intensive while limiting, but should give better (constant) speeds
*/
u32 GainL =256;
u32 GainR =256;
u32 GainSL =200;
u32 GainSR =200;
u32 GainC =200;
u32 GainLFE=256;
u32 AddCLR = 56;
u32 LowpassLFE=80;
// MISC
bool LimiterToggleEnabled=true;
int LimiterToggle=VK_SUBTRACT;
// DSP
bool dspPluginEnabled=false;
char dspPlugin[256];
int dspPluginModule=0;
bool timeStretchEnabled=false;
// OUTPUT MODULES
char AsioDriver[129]="";
/// module-specific settings
char DSoundDevice[255];
//////
char CfgFile[]="inis\\SPU2Ghz.ini";
/*| Config File Format: |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*\
+--+---------------------+------------------------+
| |
| Option=Value |
| |
| |
| Boolean Values: TRUE,YES,1,T,Y mean 'true', |
| everything else means 'false'. |
| |
| All Values are limited to 255 chars. |
| |
+-------------------------------------------------+
\*_____________________________________________*/
void CfgWriteBool(char *Section, char*Name, bool Value) {
char *Data=Value?"TRUE":"FALSE";
WritePrivateProfileString(Section,Name,Data,CfgFile);
}
void CfgWriteInt(char *Section, char*Name, int Value) {
char Data[255];
_itoa(Value,Data,10);
WritePrivateProfileString(Section,Name,Data,CfgFile);
}
void CfgWriteStr(char *Section, char*Name,char *Data) {
WritePrivateProfileString(Section,Name,Data,CfgFile);
}
/*****************************************************************************/
bool CfgReadBool(char *Section,char *Name,bool Default) {
char Data[255]="";
GetPrivateProfileString(Section,Name,"",Data,255,CfgFile);
Data[254]=0;
if(strlen(Data)==0) {
CfgWriteBool(Section,Name,Default);
return Default;
}
if(strcmp(Data,"1")==0) return true;
if(strcmp(Data,"Y")==0) return true;
if(strcmp(Data,"T")==0) return true;
if(strcmp(Data,"YES")==0) return true;
if(strcmp(Data,"TRUE")==0) return true;
return false;
}
int CfgReadInt(char *Section, char*Name,int Default) {
char Data[255]="";
GetPrivateProfileString(Section,Name,"",Data,255,CfgFile);
Data[254]=0;
if(strlen(Data)==0) {
CfgWriteInt(Section,Name,Default);
return Default;
}
return atoi(Data);
}
void CfgReadStr(char *Section, char*Name,char *Data,int DataSize,char *Default) {
int sl;
GetPrivateProfileString(Section,Name,"",Data,DataSize,CfgFile);
if(strlen(Data)==0) {
sl=(int)strlen(Default);
strncpy(Data,Default,sl>255?255:sl);
CfgWriteStr(Section,Name,Data);
}
}
/*****************************************************************************/
void ReadSettings()
{
DebugEnabled=CfgReadBool("DEBUG","Global_Debug_Enabled",0);
MsgToConsole=DebugEnabled&CfgReadBool("DEBUG","Show_Messages",0);
MsgKeyOnOff =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_Key_On_Off",0);
MsgVoiceOff =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_Voice_Off",0);
MsgDMA =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_DMA_Transfer",0);
MsgAutoDMA =DebugEnabled&MsgToConsole&CfgReadBool("DEBUG","Show_Messages_AutoDMA",0);
AccessLog =DebugEnabled&CfgReadBool("DEBUG","Log_Register_Access",0);
DMALog =DebugEnabled&CfgReadBool("DEBUG","Log_DMA_Transfers",0);
WaveLog =DebugEnabled&CfgReadBool("DEBUG","Log_WAVE_Output",0);
CoresDump =DebugEnabled&CfgReadBool("DEBUG","Dump_Info",0);
MemDump =DebugEnabled&CfgReadBool("DEBUG","Dump_Memory",0);
RegDump =DebugEnabled&CfgReadBool("DEBUG","Dump_Regs",0);
CfgReadStr("DEBUG","Access_Log_Filename",AccessLogFileName,255,"logs\\SPU2Log.txt");
CfgReadStr("DEBUG","WaveLog_Filename", WaveLogFileName, 255,"logs\\SPU2log.wav");
CfgReadStr("DEBUG","DMA4Log_Filename", DMA4LogFileName, 255,"logs\\SPU2dma4.dat");
CfgReadStr("DEBUG","DMA7Log_Filename", DMA7LogFileName, 255,"logs\\SPU2dma7.dat");
CfgReadStr("DEBUG","Info_Dump_Filename",CoresDumpFileName,255,"logs\\SPU2Cores.txt");
CfgReadStr("DEBUG","Mem_Dump_Filename", MemDumpFileName, 255,"logs\\SPU2mem.dat");
CfgReadStr("DEBUG","Reg_Dump_Filename", RegDumpFileName, 255,"logs\\SPU2regs.dat");
WaveDumpFormat=CfgReadInt("DEBUG","Wave_Log_Format",0);
Interpolation=CfgReadInt("MIXING","Interpolation",1);
AutoDMAPlayRate[0]=CfgReadInt("MIXING","AutoDMA_Play_Rate_0",0);
AutoDMAPlayRate[1]=CfgReadInt("MIXING","AutoDMA_Play_Rate_1",0);
EffectsEnabled=CfgReadBool("EFFECTS","Enable_Effects",0);
SampleRate=CfgReadInt("OUTPUT","Sample_Rate",48000);
CurBufferSize=CfgReadInt("OUTPUT","Buffer_Size",1024);
MaxBufferCount=CfgReadInt("OUTPUT","Buffer_Count",8);
if(MaxBufferCount<3) MaxBufferCount=3;
CurBufferCount=MaxBufferCount;
OutputModule=CfgReadInt("OUTPUT","Output_Module",OUTPUT_DSOUND);
VolumeMultiplier=CfgReadInt("OUTPUT","Volume_Multiplier",1);
VolumeDivisor =CfgReadInt("OUTPUT","Volume_Divisor",1);
GainL =CfgReadInt("OUTPUT","Channel_Gain_L", 256);
GainR =CfgReadInt("OUTPUT","Channel_Gain_R", 256);
GainC =CfgReadInt("OUTPUT","Channel_Gain_C", 256);
GainLFE=CfgReadInt("OUTPUT","Channel_Gain_LFE",256);
GainSL =CfgReadInt("OUTPUT","Channel_Gain_SL", 200);
GainSR =CfgReadInt("OUTPUT","Channel_Gain_SR", 200);
AddCLR =CfgReadInt("OUTPUT","Channel_Center_In_LR", 56);
LowpassLFE = CfgReadInt("OUTPUT","LFE_Lowpass_Frequency", 80);
LimitMode=CfgReadInt("OUTPUT","Speed_Limit_Mode",0);
CfgReadStr("OUTPUT","Asio_Driver_Name",AsioDriver,128,"");
CfgReadStr("DSP PLUGIN","Filename",dspPlugin,255,"");
dspPluginModule = CfgReadInt("DSP PLUGIN","ModuleNum",0);
dspPluginEnabled= CfgReadBool("DSP PLUGIN","Enabled",false);
timeStretchEnabled = CfgReadBool("DSP","Timestretch_Enable",false);
LimiterToggleEnabled = CfgReadBool("KEYS","Limiter_Toggle_Enabled",true);
LimiterToggle = CfgReadInt ("KEYS","Limiter_Toggle",VK_SUBTRACT);
CfgReadStr("DirectSound Output (Stereo)","Device",DSoundDevice,255,"");
if(VolumeMultiplier<0) VolumeMultiplier=-VolumeMultiplier;
else if(VolumeMultiplier==0) VolumeMultiplier=1;
if(VolumeDivisor<0) VolumeDivisor=-VolumeDivisor;
else if(VolumeDivisor==0) VolumeDivisor=1;
}
/*****************************************************************************/
void WriteSettings()
{
CfgWriteBool("DEBUG","Global_Debug_Enabled",DebugEnabled);
if(DebugEnabled) {
CfgWriteBool("DEBUG","Show_Messages", MsgToConsole);
CfgWriteBool("DEBUG","Show_Messages_Key_On_Off", MsgKeyOnOff);
CfgWriteBool("DEBUG","Show_Messages_Voice_Off", MsgVoiceOff);
CfgWriteBool("DEBUG","Show_Messages_DMA_Transfer",MsgDMA);
CfgWriteBool("DEBUG","Show_Messages_AutoDMA", MsgAutoDMA);
CfgWriteBool("DEBUG","Log_Register_Access",AccessLog);
CfgWriteBool("DEBUG","Log_DMA_Transfers", DMALog);
CfgWriteBool("DEBUG","Log_WAVE_Output", WaveLog);
CfgWriteBool("DEBUG","Dump_Info", CoresDump);
CfgWriteBool("DEBUG","Dump_Memory",MemDump);
CfgWriteBool("DEBUG","Dump_Regs", RegDump);
CfgWriteStr("DEBUG","Access_Log_Filename",AccessLogFileName);
CfgWriteStr("DEBUG","WaveLog_Filename", WaveLogFileName);
CfgWriteStr("DEBUG","DMA4Log_Filename", DMA4LogFileName);
CfgWriteStr("DEBUG","DMA7Log_Filename", DMA7LogFileName);
CfgWriteStr("DEBUG","Info_Dump_Filename",CoresDumpFileName);
CfgWriteStr("DEBUG","Mem_Dump_Filename", MemDumpFileName);
CfgWriteStr("DEBUG","Reg_Dump_Filename", RegDumpFileName);
CfgWriteInt("DEBUG","Wave_Log_Format", WaveDumpFormat);
}
CfgWriteInt("MIXING","Interpolation",Interpolation);
CfgWriteInt("MIXING","AutoDMA_Play_Rate_0",AutoDMAPlayRate[0]);
CfgWriteInt("MIXING","AutoDMA_Play_Rate_1",AutoDMAPlayRate[1]);
CfgWriteBool("EFFECTS","Enable_Effects",EffectsEnabled);
CfgWriteInt("OUTPUT","Output_Module",OutputModule);
CfgWriteInt("OUTPUT","Sample_Rate",SampleRate);
CfgWriteInt("OUTPUT","Buffer_Size",CurBufferSize);
CfgWriteInt("OUTPUT","Buffer_Count",MaxBufferCount);
CfgWriteInt("OUTPUT","Volume_Multiplier",VolumeMultiplier);
CfgWriteInt("OUTPUT","Volume_Divisor",VolumeDivisor);
CfgWriteInt("OUTPUT","Channel_Gain_L", GainL);
CfgWriteInt("OUTPUT","Channel_Gain_R", GainR);
CfgWriteInt("OUTPUT","Channel_Gain_C", GainC);
CfgWriteInt("OUTPUT","Channel_Gain_LFE",GainLFE);
CfgWriteInt("OUTPUT","Channel_Gain_SL", GainSL);
CfgWriteInt("OUTPUT","Channel_Gain_SR", GainSR);
CfgWriteInt("OUTPUT","Channel_Center_In_LR", AddCLR);
CfgWriteInt("OUTPUT","LFE_Lowpass_Frequency", LowpassLFE);
CfgWriteInt("OUTPUT","Speed_Limit_Mode",LimitMode);
CfgWriteStr("OUTPUT","Asio_Driver_Name",AsioDriver);
CfgWriteStr("DSP PLUGIN","Filename",dspPlugin);
CfgWriteInt("DSP PLUGIN","ModuleNum",dspPluginModule);
CfgWriteBool("DSP PLUGIN","Enabled",dspPluginEnabled);
CfgWriteBool("DSP","Timestretch_Enable",timeStretchEnabled);
CfgWriteBool("KEYS","Limiter_Toggle_Enabled",LimiterToggleEnabled);
CfgWriteInt ("KEYS","Limiter_Toggle",LimiterToggle);
CfgWriteStr("DirectSound Output (Stereo)","Device",DSoundDevice);
}
BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
int wmId,wmEvent;
char temp[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
switch(uMsg)
{
case WM_PAINT:
SET_CHECK(IDC_EFFECTS, EffectsEnabled);
SET_CHECK(IDC_DEBUG, DebugEnabled);
SET_CHECK(IDC_MSGKEY, DebugEnabled&MsgToConsole);
SET_CHECK(IDC_MSGKEY, DebugEnabled&MsgKeyOnOff);
SET_CHECK(IDC_MSGVOICE,DebugEnabled&MsgVoiceOff);
SET_CHECK(IDC_MSGDMA, DebugEnabled&MsgDMA);
SET_CHECK(IDC_MSGADMA, DebugEnabled&MsgDMA&MsgAutoDMA);
SET_CHECK(IDC_LOGREGS, AccessLog);
SET_CHECK(IDC_LOGDMA, DMALog);
SET_CHECK(IDC_LOGWAVE, WaveLog);
SET_CHECK(IDC_DUMPCORE,CoresDump);
SET_CHECK(IDC_DUMPMEM, MemDump);
SET_CHECK(IDC_DUMPREGS,RegDump);
SET_CHECK(IDC_SPEEDLIMIT,LimitMode);
return FALSE;
case WM_INITDIALOG:
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_RESETCONTENT,0,0);
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"16000");
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"22050");
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"24000");
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"32000");
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"44100");
SendMessage(GetDlgItem(hWnd,IDC_SRATE),CB_ADDSTRING,0,(LPARAM)"48000");
sprintf(temp,"%d",SampleRate);
SetDlgItemText(hWnd,IDC_SRATE,temp);
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_RESETCONTENT,0,0);
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"0 - Nearest (none)");
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"1 - Linear (mid)");
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_ADDSTRING,0,(LPARAM)"2 - Cubic (good)");
SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_SETCURSEL,Interpolation,0);
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_RESETCONTENT,0,0);
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"0 - Disabled (Emulate only)");
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"1 - waveOut (Slow/Laggy)");
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"2 - DSound (Typical)");
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"3 - DSound 5.1 (Experimental)");
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"4 - ASIO (Low Latency, BROKEN)");
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_ADDSTRING,0,(LPARAM)"5 - XAudio2 (Experimental)");
SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_SETCURSEL,OutputModule,0);
INIT_SLIDER(IDC_BUFFER,512,16384,4096,2048,512);
SendMessage(GetDlgItem(hWnd,IDC_BUFFER),TBM_SETPOS,TRUE,CurBufferSize);
sprintf(temp,"%d",CurBufferSize);
SetWindowText(GetDlgItem(hWnd,IDC_BSIZE),temp);
sprintf(temp,"%d",MaxBufferCount);
SetWindowText(GetDlgItem(hWnd,IDC_BCOUNT),temp);
ENABLE_CONTROL(IDC_MSGSHOW, DebugEnabled);
ENABLE_CONTROL(IDC_MSGKEY, DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGVOICE,DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGDMA, DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGADMA, DebugEnabled&MsgToConsole&MsgDMA);
ENABLE_CONTROL(IDC_LOGREGS, DebugEnabled);
ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled);
ENABLE_CONTROL(IDC_LOGWAVE, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPCORE,DebugEnabled);
ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPREGS,DebugEnabled);
SET_CHECK(IDC_EFFECTS, EffectsEnabled);
SET_CHECK(IDC_DEBUG, DebugEnabled);
SET_CHECK(IDC_MSGSHOW, MsgToConsole);
SET_CHECK(IDC_MSGKEY, MsgKeyOnOff);
SET_CHECK(IDC_MSGVOICE,MsgVoiceOff);
SET_CHECK(IDC_MSGDMA, MsgDMA);
SET_CHECK(IDC_MSGADMA, MsgAutoDMA);
SET_CHECK(IDC_LOGREGS, AccessLog);
SET_CHECK(IDC_LOGDMA, DMALog);
SET_CHECK(IDC_LOGWAVE, WaveLog);
SET_CHECK(IDC_DUMPCORE,CoresDump);
SET_CHECK(IDC_DUMPMEM, MemDump);
SET_CHECK(IDC_DUMPREGS,RegDump);
SET_CHECK(IDC_SPEEDLIMIT,LimitMode);
SET_CHECK(IDC_DSP_ENABLE,dspPluginEnabled);
SET_CHECK(IDC_TS_ENABLE,timeStretchEnabled);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDOK:
GetDlgItemText(hWnd,IDC_SRATE,temp,20);
temp[19]=0;
SampleRate=atoi(temp);
GetDlgItemText(hWnd,IDC_BSIZE,temp,20);
temp[19]=0;
CurBufferSize=atoi(temp);
if(CurBufferSize<512) CurBufferSize=512;
if(CurBufferSize>16384) CurBufferSize=16384;
GetDlgItemText(hWnd,IDC_BCOUNT,temp,20);
temp[19]=0;
MaxBufferCount=atoi(temp);
if(MaxBufferCount<4) MaxBufferCount=4;
if(MaxBufferCount>50) MaxBufferCount=50;
Interpolation=(int)SendMessage(GetDlgItem(hWnd,IDC_INTERPOLATE),CB_GETCURSEL,0,0);
OutputModule=(int)SendMessage(GetDlgItem(hWnd,IDC_OUTPUT),CB_GETCURSEL,0,0);
/*
if((BufferSize*CurBufferCount)<9600)
{
int ret=MessageBoxEx(hWnd,"The total buffer space is too small and might cause problems.\n"
"Press [Cancel] to go back and increase the buffer size or number.",
"WARNING",MB_OKCANCEL | MB_ICONEXCLAMATION, 0);
if(ret==IDCANCEL)
break;
}
*/
DebugEnabled=DebugEnabled;
MsgToConsole=DebugEnabled&MsgToConsole;
MsgKeyOnOff =DebugEnabled&MsgToConsole&MsgKeyOnOff;
MsgVoiceOff =DebugEnabled&MsgToConsole&MsgVoiceOff;
MsgDMA =DebugEnabled&MsgToConsole&MsgDMA;
MsgAutoDMA =DebugEnabled&MsgToConsole&MsgAutoDMA;
AccessLog =DebugEnabled&AccessLog;
DMALog =DebugEnabled&DMALog;
WaveLog =DebugEnabled&WaveLog;
CoresDump =DebugEnabled&CoresDump;
MemDump =DebugEnabled&MemDump;
RegDump =DebugEnabled&RegDump;
WriteSettings();
EndDialog(hWnd,0);
break;
case IDCANCEL:
EndDialog(hWnd,0);
break;
case IDC_OUTCONF:
SndConfigure(hWnd);
break;
HANDLE_CHECK(IDC_EFFECTS,EffectsEnabled);
HANDLE_CHECKNB(IDC_DEBUG,DebugEnabled);
ENABLE_CONTROL(IDC_MSGSHOW, DebugEnabled);
ENABLE_CONTROL(IDC_MSGKEY, DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGVOICE,DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGDMA, DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGADMA, DebugEnabled&MsgToConsole&MsgDMA);
ENABLE_CONTROL(IDC_LOGREGS, DebugEnabled);
ENABLE_CONTROL(IDC_LOGDMA, DebugEnabled);
ENABLE_CONTROL(IDC_LOGWAVE, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPCORE,DebugEnabled);
ENABLE_CONTROL(IDC_DUMPMEM, DebugEnabled);
ENABLE_CONTROL(IDC_DUMPREGS,DebugEnabled);
break;
HANDLE_CHECKNB(IDC_MSGSHOW,MsgToConsole);
ENABLE_CONTROL(IDC_MSGKEY, DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGVOICE,DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGDMA, DebugEnabled&MsgToConsole);
ENABLE_CONTROL(IDC_MSGADMA, DebugEnabled&MsgToConsole&MsgDMA);
break;
HANDLE_CHECK(IDC_MSGKEY,MsgKeyOnOff);
HANDLE_CHECK(IDC_MSGVOICE,MsgVoiceOff);
HANDLE_CHECKNB(IDC_MSGDMA,MsgDMA);
ENABLE_CONTROL(IDC_MSGADMA, DebugEnabled&MsgToConsole&MsgDMA);
break;
HANDLE_CHECK(IDC_MSGADMA,MsgAutoDMA);
HANDLE_CHECK(IDC_LOGREGS,AccessLog);
HANDLE_CHECK(IDC_LOGDMA, DMALog);
HANDLE_CHECK(IDC_LOGWAVE,WaveLog);
HANDLE_CHECK(IDC_DUMPCORE,CoresDump);
HANDLE_CHECK(IDC_DUMPMEM, MemDump);
HANDLE_CHECK(IDC_DUMPREGS,RegDump);
HANDLE_CHECK(IDC_SPEEDLIMIT,LimitMode);
HANDLE_CHECK(IDC_DSP_ENABLE,dspPluginEnabled);
HANDLE_CHECK(IDC_TS_ENABLE,timeStretchEnabled);
default:
return FALSE;
}
break;
case WM_HSCROLL:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch(wmId) {
//case TB_ENDTRACK:
//case TB_THUMBPOSITION:
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0);
case TB_THUMBTRACK:
if(wmEvent<512) wmEvent=512;
if(wmEvent>24000) wmEvent=24000;
SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent);
sprintf(temp,"%d",wmEvent);
SetDlgItemText(hWnd,IDC_BSIZE,temp);
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
void configure()
{
INT_PTR ret;
ReadSettings();
ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_CONFIG),GetActiveWindow(),(DLGPROC)ConfigProc,1);
if(ret==-1)
{
MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0);
return;
}
ReadSettings();
}

99
plugins/spu2ghz/config.h Normal file
View File

@ -0,0 +1,99 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#ifndef CONFIG_H_INCLUDED
#define CONFIG_H_INCLUDED
extern bool DebugEnabled;
extern bool MsgToConsole;
extern bool MsgKeyOnOff;
extern bool MsgVoiceOff;
extern bool MsgDMA;
extern bool MsgAutoDMA;
extern bool AccessLog;
extern bool DMALog;
extern bool WaveLog;
extern bool CoresDump;
extern bool MemDump;
extern bool RegDump;
extern char AccessLogFileName[255];
extern char WaveLogFileName[255];
extern char DMA4LogFileName[255];
extern char DMA7LogFileName[255];
extern char CoresDumpFileName[255];
extern char MemDumpFileName[255];
extern char RegDumpFileName[255];
extern int Interpolation;
extern int WaveDumpFormat;
extern int SampleRate;
extern bool EffectsEnabled;
extern int AutoDMAPlayRate[2];
extern int OutputModule;
extern int CurBufferSize;
extern int CurBufferCount;
extern int MaxBufferCount;
extern int VolumeMultiplier;
extern int VolumeDivisor;
extern int LimitMode;
extern char AsioDriver[129];
extern u32 GainL;
extern u32 GainR;
extern u32 GainC;
extern u32 GainLFE;
extern u32 GainSL;
extern u32 GainSR;
extern u32 AddCLR;
extern u32 LowpassLFE;
extern char dspPlugin[];
extern int dspPluginModule;
extern bool dspPluginEnabled;
extern bool timeStretchEnabled;
extern bool LimiterToggleEnabled;
extern int LimiterToggle;
/// module-specific settings
extern char DSoundDevice[];
//////
void ReadSettings();
void WriteSettings();
void configure();
#endif // CONFIG_H_INCLUDED

260
plugins/spu2ghz/debug.cpp Normal file
View File

@ -0,0 +1,260 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#include "spu2.h"
int crazy_debug=0;
char s[4096];
FILE *spu2Log;
void FileLog(const char *fmt, ...) {
#ifdef SPU2_LOG
int n;
va_list list;
if(!DebugEnabled) return;
if(!AccessLog) return;
if(!spu2Log) return;
va_start(list, fmt);
n=vsprintf(s,fmt, list);
va_end(list);
fputs(s,spu2Log);
fflush(spu2Log);
#if 0
if(crazy_debug)
{
fputs(s,stderr);
fflush(stderr);
}
#endif
#endif
}
void ConLog(const char *fmt, ...) {
#ifdef SPU2_LOG
int n;
va_list list;
if(!DebugEnabled) return;
if(!MsgToConsole) return;
va_start(list, fmt);
n=vsprintf(s,fmt, list);
va_end(list);
fputs(s,stderr);
fflush(stderr);
if(spu2Log)
{
fputs(s,spu2Log);
fflush(spu2Log);
}
#endif
}
void DoFullDump() {
#ifdef SPU2_LOG
FILE *dump;
u8 c=0, v=0;
if(MemDump) {
dump=fopen(MemDumpFileName,"wb");
if (dump) {
fwrite(_spu2mem,0x200000,1,dump);
fclose(dump);
}
}
if(RegDump) {
dump=fopen(RegDumpFileName,"wb");
if (dump) {
fwrite(spu2regs,0x2000,1,dump);
fclose(dump);
}
}
if(!CoresDump) return;
dump=fopen(CoresDumpFileName,"wt");
if (dump) {
for(c=0;c<2;c++) {
fprintf(dump,"#### CORE %d DUMP.\n",c);
fprintf(dump,"Master Volume for Left Channel: %x\n"
" - Value: %x\n"
" - Mode: %x\n"
" - Increment: %x\n",
Cores[c].MasterL.Reg_VOL,
Cores[c].MasterL.Value,
Cores[c].MasterL.Mode,
Cores[c].MasterL.Increment);
fprintf(dump,"Master Volume for Right Channel: %x\n"
" - Value: %x\n"
" - Mode: %x\n"
" - Increment: %x\n",
Cores[c].MasterR.Reg_VOL,
Cores[c].MasterR.Value,
Cores[c].MasterR.Mode,
Cores[c].MasterR.Increment);
fprintf(dump,"Volume for External Data Input (Left Channel): %x\n",Cores[c].ExtL);
fprintf(dump,"Volume for External Data Input (Right Channel): %x\n",Cores[c].ExtR);
fprintf(dump,"Volume for Sound Data Input (Left Channel): %x\n",Cores[c].InpL);
fprintf(dump,"Volume for Sound Data Input (Right Channel): %x\n",Cores[c].InpR);
fprintf(dump,"Volume for Output from Effects (Left Channel): %x\n",Cores[c].FxL);
fprintf(dump,"Volume for Output from Effects (Right Channel): %x\n",Cores[c].FxR);
fprintf(dump,"Interrupt Address: %x\n",Cores[c].IRQA);
fprintf(dump,"DMA Transfer Start Address: %x\n",Cores[c].TSA);
fprintf(dump,"External Input to Direct Output (Left): %s\n",Cores[c].ExtDryL?"Yes":"No");
fprintf(dump,"External Input to Direct Output (Right): %s\n",Cores[c].ExtDryR?"Yes":"No");
fprintf(dump,"External Input to Effects (Left): %s\n",Cores[c].ExtWetL?"Yes":"No");
fprintf(dump,"External Input to Effects (Right): %s\n",Cores[c].ExtWetR?"Yes":"No");
fprintf(dump,"Sound Data Input to Direct Output (Left): %s\n",Cores[c].SndDryL?"Yes":"No");
fprintf(dump,"Sound Data Input to Direct Output (Right): %s\n",Cores[c].SndDryR?"Yes":"No");
fprintf(dump,"Sound Data Input to Effects (Left): %s\n",Cores[c].SndWetL?"Yes":"No");
fprintf(dump,"Sound Data Input to Effects (Right): %s\n",Cores[c].SndWetR?"Yes":"No");
fprintf(dump,"Voice Data Input to Direct Output (Left): %s\n",Cores[c].InpDryL?"Yes":"No");
fprintf(dump,"Voice Data Input to Direct Output (Right): %s\n",Cores[c].InpDryR?"Yes":"No");
fprintf(dump,"Voice Data Input to Effects (Left): %s\n",Cores[c].InpWetL?"Yes":"No");
fprintf(dump,"Voice Data Input to Effects (Right): %s\n",Cores[c].InpWetR?"Yes":"No");
fprintf(dump,"IRQ Enabled: %s\n",Cores[c].IRQEnable?"Yes":"No");
fprintf(dump,"Effects Enabled: %s\n",Cores[c].FxEnable?"Yes":"No");
fprintf(dump,"Mute Enabled: %s\n",Cores[c].Mute?"Yes":"No");
fprintf(dump,"Noise Clock: %d\n",Cores[c].NoiseClk);
fprintf(dump,"DMA Bits: %d\n",Cores[c].DMABits);
fprintf(dump,"Effects Start: %x\n",Cores[c].EffectsStartA);
fprintf(dump,"Effects End: %x\n",Cores[c].EffectsEndA);
fprintf(dump,"Registers:\n");
fprintf(dump," - PMON: %x\n",Cores[c].Regs.PMON);
fprintf(dump," - NON: %x\n",Cores[c].Regs.NON);
fprintf(dump," - VMIXL: %x\n",Cores[c].Regs.VMIXL);
fprintf(dump," - VMIXR: %x\n",Cores[c].Regs.VMIXR);
fprintf(dump," - VMIXEL: %x\n",Cores[c].Regs.VMIXEL);
fprintf(dump," - VMIXER: %x\n",Cores[c].Regs.VMIXER);
fprintf(dump," - MMIX: %x\n",Cores[c].Regs.VMIXEL);
fprintf(dump," - ENDX: %x\n",Cores[c].Regs.VMIXER);
fprintf(dump," - STATX: %x\n",Cores[c].Regs.VMIXEL);
fprintf(dump," - ATTR: %x\n",Cores[c].Regs.VMIXER);
for(v=0;v<24;v++) {
fprintf(dump,"Voice %d:\n",v);
fprintf(dump," - Volume for Left Channel: %x\n"
" - Value: %x\n"
" - Mode: %x\n"
" - Increment: %x\n",
Cores[c].Voices[v].VolumeL.Reg_VOL,
Cores[c].Voices[v].VolumeL.Value,
Cores[c].Voices[v].VolumeL.Mode,
Cores[c].Voices[v].VolumeL.Increment);
fprintf(dump," - Volume for Right Channel: %x\n"
" - Value: %x\n"
" - Mode: %x\n"
" - Increment: %x\n",
Cores[c].Voices[v].VolumeR.Reg_VOL,
Cores[c].Voices[v].VolumeR.Value,
Cores[c].Voices[v].VolumeR.Mode,
Cores[c].Voices[v].VolumeR.Increment);
fprintf(dump," - ADSR Envelope: %x & %x\n"
" - Ar: %x\n"
" - Am: %x\n"
" - Dr: %x\n"
" - Sl: %x\n"
" - Sr: %x\n"
" - Sm: %x\n"
" - Rr: %x\n"
" - Rm: %x\n"
" - Phase: %x\n"
" - Value: %x\n",
Cores[c].Voices[v].ADSR.Reg_ADSR1,
Cores[c].Voices[v].ADSR.Reg_ADSR2,
Cores[c].Voices[v].ADSR.Ar,
Cores[c].Voices[v].ADSR.Am,
Cores[c].Voices[v].ADSR.Dr,
Cores[c].Voices[v].ADSR.Sl,
Cores[c].Voices[v].ADSR.Sr,
Cores[c].Voices[v].ADSR.Sm,
Cores[c].Voices[v].ADSR.Rr,
Cores[c].Voices[v].ADSR.Rm,
Cores[c].Voices[v].ADSR.Phase,
Cores[c].Voices[v].ADSR.Value);
fprintf(dump," - Pitch: %x\n",Cores[c].Voices[v].Pitch);
fprintf(dump," - Modulated: %s\n",Cores[c].Voices[v].Modulated?"Yes":"No");
fprintf(dump," - Source: %s\n",Cores[c].Voices[v].Noise?"Noise":"Wave");
fprintf(dump," - Direct Output for Left Channel: %s\n",Cores[c].Voices[v].DryL?"Yes":"No");
fprintf(dump," - Direct Output for Right Channel: %s\n",Cores[c].Voices[v].DryR?"Yes":"No");
fprintf(dump," - Effects Output for Left Channel: %s\n",Cores[c].Voices[v].WetL?"Yes":"No");
fprintf(dump," - Effects Output for Right Channel: %s\n",Cores[c].Voices[v].WetR?"Yes":"No");
fprintf(dump," - Loop Start Adress: %x\n",Cores[c].Voices[v].LoopStartA);
fprintf(dump," - Sound Start Adress: %x\n",Cores[c].Voices[v].StartA);
fprintf(dump," - Next Data Adress: %x\n",Cores[c].Voices[v].NextA);
fprintf(dump," - Play Start Cycle: %d\n",Cores[c].Voices[v].PlayCycle);
fprintf(dump," - Play Status: %s\n",(Cores[c].Voices[v].ADSR.Phase>0)?"Playing":"Not Playing");
fprintf(dump," - Block Sample: %d\n",Cores[c].Voices[v].SCurrent);
}
fprintf(dump,"#### END OF DUMP.\n\n");
}
}
fclose(dump);
dump=fopen("logs/effects.txt","wt");
if (dump) {
for(c=0;c<2;c++) {
fprintf(dump,"#### CORE %d EFFECTS PROCESSOR DUMP.\n",c);
fprintf(dump," - IN_COEF_L: %x\n",Cores[c].Revb.IN_COEF_R);
fprintf(dump," - IN_COEF_R: %x\n",Cores[c].Revb.IN_COEF_L);
fprintf(dump," - FB_ALPHA: %x\n",Cores[c].Revb.FB_ALPHA);
fprintf(dump," - FB_X: %x\n",Cores[c].Revb.FB_X);
fprintf(dump," - FB_SRC_A: %x\n",Cores[c].Revb.FB_SRC_A);
fprintf(dump," - FB_SRC_B: %x\n",Cores[c].Revb.FB_SRC_B);
fprintf(dump," - IIR_ALPHA: %x\n",Cores[c].Revb.IIR_ALPHA);
fprintf(dump," - IIR_COEF: %x\n",Cores[c].Revb.IIR_COEF);
fprintf(dump," - IIR_SRC_A0: %x\n",Cores[c].Revb.IIR_SRC_A0);
fprintf(dump," - IIR_SRC_A1: %x\n",Cores[c].Revb.IIR_SRC_A1);
fprintf(dump," - IIR_SRC_B1: %x\n",Cores[c].Revb.IIR_SRC_B0);
fprintf(dump," - IIR_SRC_B0: %x\n",Cores[c].Revb.IIR_SRC_B1);
fprintf(dump," - IIR_DEST_A0: %x\n",Cores[c].Revb.IIR_DEST_A0);
fprintf(dump," - IIR_DEST_A1: %x\n",Cores[c].Revb.IIR_DEST_A1);
fprintf(dump," - IIR_DEST_B0: %x\n",Cores[c].Revb.IIR_DEST_B0);
fprintf(dump," - IIR_DEST_B1: %x\n",Cores[c].Revb.IIR_DEST_B1);
fprintf(dump," - ACC_COEF_A: %x\n",Cores[c].Revb.ACC_COEF_A);
fprintf(dump," - ACC_COEF_B: %x\n",Cores[c].Revb.ACC_COEF_B);
fprintf(dump," - ACC_COEF_C: %x\n",Cores[c].Revb.ACC_COEF_C);
fprintf(dump," - ACC_COEF_D: %x\n",Cores[c].Revb.ACC_COEF_D);
fprintf(dump," - ACC_SRC_A0: %x\n",Cores[c].Revb.ACC_SRC_A0);
fprintf(dump," - ACC_SRC_A1: %x\n",Cores[c].Revb.ACC_SRC_A1);
fprintf(dump," - ACC_SRC_B0: %x\n",Cores[c].Revb.ACC_SRC_B0);
fprintf(dump," - ACC_SRC_B1: %x\n",Cores[c].Revb.ACC_SRC_B1);
fprintf(dump," - ACC_SRC_C0: %x\n",Cores[c].Revb.ACC_SRC_C0);
fprintf(dump," - ACC_SRC_C1: %x\n",Cores[c].Revb.ACC_SRC_C1);
fprintf(dump," - ACC_SRC_D0: %x\n",Cores[c].Revb.ACC_SRC_D0);
fprintf(dump," - ACC_SRC_D1: %x\n",Cores[c].Revb.ACC_SRC_D1);
fprintf(dump," - MIX_DEST_A0: %x\n",Cores[c].Revb.MIX_DEST_A0);
fprintf(dump," - MIX_DEST_A1: %x\n",Cores[c].Revb.MIX_DEST_A1);
fprintf(dump," - MIX_DEST_B0: %x\n",Cores[c].Revb.MIX_DEST_B0);
fprintf(dump," - MIX_DEST_B1: %x\n",Cores[c].Revb.MIX_DEST_B1);
fprintf(dump,"#### END OF DUMP.\n\n");
}
fclose(dump);
}
#endif
}

37
plugins/spu2ghz/debug.h Normal file
View File

@ -0,0 +1,37 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#ifndef DEBUG_H_INCLUDED
#define DEBUG_H_INCLUDED
extern FILE *spu2Log;
extern int Log;
void FileLog(const char *fmt, ...);
void ConLog(const char *fmt, ...);
void DoFullDump();
extern int wavedump_ok;
int wavedump_open();
void wavedump_close();
void wavedump_write(s16 left,s16 right);
#endif // DEBUG_H_INCLUDED //

384
plugins/spu2ghz/decoder.cpp Normal file
View File

@ -0,0 +1,384 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#include "spu2.h"
extern "C" {
#include "liba52/inttypes.h"
#include "liba52/a52.h"
#include "liba52/mm_accel.h"
}
extern u32 spdif_read_data(u8 *buff, u32 max_data);
#define DATA_SIZE 0x100000
u32 use51=0;
u8 databuffer[DATA_SIZE];
u32 data_in_buffer;
s32 output_buffer[0x10000][6];
s32 output_write_cursor=0;
s32 output_read_cursor=0;
s32 output_buffer_data=0;
int flags,srate,bitrate;
#define CHANNEL_CENTER 1
#define CHANNEL_STEREO 2
#define CHANNEL_SURROUND 4
#define CHANNEL_LFE 8
int sample_flags = 0;
int frame_size;
a52_state_t* ac3dec;
sample_t *decode_buffer = NULL;
u32 data_rate=4;
int state=0;
FILE *fSpdifDump;
extern u32 core;
void __fastcall ReadInput(s32& PDataL,s32& PDataR);
union spdif_frame { // total size: 32bits
struct {
u32 preamble:4; //4
u32 databits:24; //28
u32 valid:1; //29
u32 subcode:1; //30
u32 chanstat:1; //31
u32 parity:1; //32 // parity not including preamble
} bits;
u32 whole;
};
union spdif_block {
spdif_frame frames[192];
u8 bytes [192*4];
};
/*
spdif_block bbuffer[2];
u8 *bbuff = bbuffer[0].bytes;
u32 bbuff_bytes = 0;
*/
bool check_frame(spdif_frame f)
{
u32 w = f.whole>>4;
u32 t = 0;
for(int i=0;i>28;i++)
{
t=t^(w&1);
w>>=1;
}
return (t==0)&&(f.bits.valid);
}
void spdif_Write(s32 data)
{
spdif_frame f;
f.whole=data;
if(check_frame(f))
{
int dec = f.bits.databits;
databuffer[data_in_buffer++]=(dec )&0xFF;
databuffer[data_in_buffer++]=(dec>> 8)&0xFF;
databuffer[data_in_buffer++]=(dec>>16)&0xFF;
}
}
void spdif_remove_data(int bytes)
{
if(bytes<data_in_buffer)
{
memcpy(databuffer,databuffer+bytes,data_in_buffer-bytes);
}
data_in_buffer-=bytes;
}
s32 stoi(sample_t n) //input: [-1..1]
{
s32 sign=(n<0) + (n>0)*-1; //1 if positive, -1 if negative, 0 otherwise
n=abs(n)+1; //make it [1..2]
s32 k=*(s32*)&n;
k=k&0x7FFFFF;
return k*sign;
}
void spdif_update()
{
s32 Data,Zero;
for(int i=0;i<data_rate;i++)
{
core=0;
ReadInput(Data,Zero);
if(fSpdifDump)
{
fwrite(&Data,4,1,fSpdifDump);
fwrite(&Zero,4,1,fSpdifDump);
}
if(ac3dec)
spdif_Write(Data);
}
if(!ac3dec) return;
if(state==0)
{
if(data_in_buffer<7) return;
if(databuffer[0]!=0)
{
flags=0;
}
frame_size = a52_syncinfo (databuffer, &flags, &srate, &bitrate);
if(frame_size==0)
{
spdif_remove_data(1);
}
else
{
state=1;
}
}
if(state==1)
{
if(data_in_buffer<frame_size) return;
flags = A52_ADJUST_LEVEL;
if(use51) flags|=A52_3F2R|A52_LFE;
else flags|=A52_STEREO;
sample_t level=1;
a52_frame(ac3dec,databuffer,&flags,&level,0);
//decode
for(int i=0;i<6;i++)
{
a52_block(ac3dec);
// processing
for(int j=0;j<256;j++)
{
s32* samples = output_buffer[output_write_cursor];
sample_flags=0;
int output_cursor=j;
int n=0;
if(flags&A52_LFE)
{
sample_flags|=CHANNEL_LFE;
samples[3] = stoi(decode_buffer[(0<<8)+output_cursor]); //lfe
n=1;
}
switch(flags&(~A52_LFE))
{
case A52_STEREO:
sample_flags |= CHANNEL_STEREO;
samples[0] = stoi(decode_buffer[((n+0)<<8)+output_cursor]); //l
samples[1] = stoi(decode_buffer[((n+1)<<8)+output_cursor]); //r
samples[2] = 0; //c
samples[4] = 0; //sl
samples[5] = 0; //sr
break;
case A52_2F1R:
sample_flags |= CHANNEL_STEREO|CHANNEL_SURROUND;
samples[0] = stoi(decode_buffer[((n+0)<<8)+output_cursor]); //l
samples[1] = stoi(decode_buffer[((n+1)<<8)+output_cursor]); //r
samples[2] = 0; //c
samples[4] = stoi(decode_buffer[((n+2)<<8)+output_cursor]); //sl
samples[5] = stoi(decode_buffer[((n+2)<<8)+output_cursor]); //sr
break;
case A52_2F2R:
sample_flags |= CHANNEL_STEREO|CHANNEL_SURROUND;
samples[0] = stoi(decode_buffer[((n+0)<<8)+output_cursor]); //l
samples[1] = stoi(decode_buffer[((n+1)<<8)+output_cursor]); //r
samples[2] = 0; //c
samples[4] = stoi(decode_buffer[((n+2)<<8)+output_cursor]); //sl
samples[5] = stoi(decode_buffer[((n+3)<<8)+output_cursor]); //sr
break;
case A52_3F:
sample_flags |= CHANNEL_STEREO|CHANNEL_CENTER;
samples[0] = stoi(decode_buffer[((n+0)<<8)+output_cursor]); //l
samples[1] = stoi(decode_buffer[((n+2)<<8)+output_cursor]); //r
samples[2] = stoi(decode_buffer[((n+1)<<8)+output_cursor]); //c
samples[4] = 0; //sl
samples[5] = 0; //sr
break;
case A52_3F1R:
sample_flags |= CHANNEL_STEREO|CHANNEL_SURROUND|CHANNEL_CENTER;
samples[0] = stoi(decode_buffer[((n+0)<<8)+output_cursor]); //l
samples[1] = stoi(decode_buffer[((n+2)<<8)+output_cursor]); //r
samples[2] = stoi(decode_buffer[((n+1)<<8)+output_cursor]); //c
samples[4] = stoi(decode_buffer[((n+2)<<8)+output_cursor]); //sl
samples[5] = stoi(decode_buffer[((n+2)<<8)+output_cursor]); //sr
break;
case A52_3F2R:
sample_flags |= CHANNEL_STEREO|CHANNEL_SURROUND|CHANNEL_CENTER;
samples[0] = stoi(decode_buffer[((n+0)<<8)+output_cursor]); //l
samples[1] = stoi(decode_buffer[((n+2)<<8)+output_cursor]); //r
samples[2] = stoi(decode_buffer[((n+1)<<8)+output_cursor]); //c
samples[4] = stoi(decode_buffer[((n+2)<<8)+output_cursor]); //sl
samples[5] = stoi(decode_buffer[((n+2)<<8)+output_cursor]); //sr
break;
default:
samples[0] = stoi(decode_buffer[((n+0)<<8)+output_cursor]); //l
samples[1] = stoi(decode_buffer[((n+1)<<8)+output_cursor]); //r
samples[2] = 0; //c
samples[4] = 0; //sl
samples[5] = 0; //sr
break;
}
output_write_cursor=(output_write_cursor+1)&0xFFFF;
output_buffer_data++;
}
}
spdif_remove_data(frame_size);
}
}
u32 spdif_init()
{
data_rate=1; // words/tick
ac3dec = a52_init(0);
if(!ac3dec) return 1;
decode_buffer = a52_samples(ac3dec);
a52_dynrng (ac3dec, NULL, NULL);
data_in_buffer=0;
fSpdifDump = fopen("logs/spdif.dat","wb");
return 0;
}
void spdif_set51(u32 is_5_1_out)
{
use51 = is_5_1_out;
}
void spdif_shutdown()
{
if(ac3dec) a52_free(ac3dec);
ac3dec=NULL;
if(fSpdifDump)
fclose(fSpdifDump);
}
int spdif_decode_one(s32 *channels)
{
channels[0]=0;
channels[1]=0;
channels[2]=0;
channels[3]=0;
channels[4]=0;
channels[5]=0;
if(output_buffer_data==0) return 0;
memcpy(channels,output_buffer[output_read_cursor],4*6);
output_read_cursor=(output_read_cursor+1)&0xFFFF;
output_buffer_data--;
return sample_flags;
}
void spdif_get_samples(s32*samples)
{
s32 channels[6];
s32 flags = spdif_decode_one(channels);
if(use51)
{
samples[0]=0;
samples[1]=0;
samples[2]=0;
samples[3]=0;
samples[4]=0;
samples[5]=0;
if(flags&CHANNEL_STEREO)
{
samples[0]=channels[0];
samples[1]=channels[1];
}
if(flags&CHANNEL_CENTER)
{
samples[2]=channels[2];
}
if(flags&CHANNEL_LFE)
{
samples[3]=channels[3];
}
if(flags&CHANNEL_SURROUND)
{
samples[4]=channels[4];
samples[5]=channels[5];
}
}
else // downmix to stereo (no DPL2 encoding... yet ;)
{
samples[0]=0;
samples[1]=0;
if(flags&CHANNEL_STEREO)
{
samples[0]=channels[0];
samples[1]=channels[1];
}
if(flags&CHANNEL_CENTER)
{
samples[0]+=channels[2];
samples[1]+=channels[2];
}
if(flags&CHANNEL_LFE)
{
samples[0]+=channels[3];
samples[1]+=channels[3];
}
if(flags&CHANNEL_SURROUND)
{
samples[0]+=channels[4];
samples[1]+=channels[5];
}
}
}

293
plugins/spu2ghz/defs.h Normal file
View File

@ -0,0 +1,293 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#ifndef DEFS_H_INCLUDED
#define DEFS_H_INCLUDED
typedef enum {SPU2_VOL_MODE_CONST,SPU2_VOL_MODE_PLIN,SPU2_VOL_MODE_NLIN,SPU2_VOL_MODE_PLOG,SPU2_VOL_MODE_NLOG} V_VolMode;
typedef struct {
u16 Reg_VOL;
s16 Value; //also Reg_VOLX
s8 Increment;
s8 Mode;
} V_Volume;
typedef struct {
u16 Reg_ADSR1;
u16 Reg_ADSR2;
//also Reg_ENVX
u32 Value;
// Phase
u8 Phase;
//Attack Rate
u8 Ar;
//Attack Mode
u8 Am;
//Decay Rate
u8 Dr;
//Sustain Level
u8 Sl;
//Sustain Rate
u8 Sr;
//Sustain Mode
u8 Sm;
//Release Rate
u8 Rr;
//Release Mode
u8 Rm;
//Ready To Release
u8 Releasing;
} V_ADSR;
typedef struct {
// SPU2 cycle where the Playing started
u32 PlayCycle;
// Left Volume
V_Volume VolumeL;
// Right Volume
V_Volume VolumeR;
// Envelope
V_ADSR ADSR;
// Pitch (also Reg_PITCH)
s16 Pitch;
// Pitch Modulated by previous voice
s8 Modulated;
// Source (Wave/Noise)
s8 Noise;
// Direct Output for Left Channel
s8 DryL;
// Direct Output for Right Channel
s8 DryR;
// Effect Output for Left Channel
s8 WetL;
// Effect Output for Right Channel
s8 WetR;
// Loop Start Adress (also Reg_LSAH/L)
u32 LoopStartA;
// Sound Start Adress (also Reg_SSAH/L)
u32 StartA;
// Next Read Data Adress (also Reg_NAXH/L)
u32 NextA;
// Voice Decoding State
s32 Prev1;
s32 Prev2;
s8 LoopMode;
s8 LoopStart;
s8 Loop;
s8 LoopEnd;
s32 SP;
s32 PV1;
s32 PV2;
s32 PV3;
s32 PV4;
s32 OutX;
s8 FirstBlock;
s32 PeakX;
s32 SampleData;
s32 SBuffer[32];
s32 SCurrent;
s32 displayPeak;
s32 lastSetStartA;
s32 lastStopReason;
} V_Voice;
typedef struct {
u16 IN_COEF_L;
u16 IN_COEF_R;
u32 FB_SRC_A;
u32 FB_SRC_B;
u16 FB_ALPHA;
u16 FB_X;
u32 IIR_SRC_A0;
u32 IIR_SRC_A1;
u32 IIR_SRC_B1;
u32 IIR_SRC_B0;
u32 IIR_DEST_A0;
u32 IIR_DEST_A1;
u32 IIR_DEST_B0;
u32 IIR_DEST_B1;
u16 IIR_ALPHA;
u16 IIR_COEF;
u32 ACC_SRC_A0;
u32 ACC_SRC_A1;
u32 ACC_SRC_B0;
u32 ACC_SRC_B1;
u32 ACC_SRC_C0;
u32 ACC_SRC_C1;
u32 ACC_SRC_D0;
u32 ACC_SRC_D1;
u16 ACC_COEF_A;
u16 ACC_COEF_B;
u16 ACC_COEF_C;
u16 ACC_COEF_D;
u32 MIX_DEST_A0;
u32 MIX_DEST_A1;
u32 MIX_DEST_B0;
u32 MIX_DEST_B1;
} V_Reverb;
typedef struct {
u16 Out;
u16 Info;
u16 Unknown1;
u16 Mode;
u16 Media;
u16 Unknown2;
u16 Protection;
} V_SPDIF;
typedef struct {
u32 PMON;
u32 NON;
u32 VMIXL;
u32 VMIXR;
u32 VMIXEL;
u32 VMIXER;
u16 MMIX;
u32 ENDX;
u16 STATX;
u16 ATTR;
u16 _1AC;
} V_CoreRegs;
typedef struct {
// Core Voices
V_Voice Voices[24];
// Master Volume for Left Channel
V_Volume MasterL;
// Master Volume for Right Channel
V_Volume MasterR;
// Volume for External Data Input (Left Channel)
u16 ExtL;
// Volume for External Data Input (Right Channel)
u16 ExtR;
// Volume for Sound Data Input (Left Channel)
u16 InpL;
// Volume for Sound Data Input (Right Channel)
u16 InpR;
// Volume for Output from Effects (Left Channel)
u16 FxL;
// Volume for Output from Effects (Right Channel)
u16 FxR;
// Interrupt Address
u32 IRQA;
// DMA Transfer Start Address
u32 TSA;
// DMA Transfer Data Address (Internal...)
u32 TDA;
// External Input to Direct Output (Left)
s8 ExtDryL;
// External Input to Direct Output (Right)
s8 ExtDryR;
// External Input to Effects (Left)
s8 ExtWetL;
// External Input to Effects (Right)
s8 ExtWetR;
// Sound Data Input to Direct Output (Left)
s8 InpDryL;
// Sound Data Input to Direct Output (Right)
s8 InpDryR;
// Sound Data Input to Effects (Left)
s8 InpWetL;
// Sound Data Input to Effects (Right)
s8 InpWetR;
// Voice Data to Direct Output (Left)
s8 SndDryL;
// Voice Data to Direct Output (Right)
s8 SndDryR;
// Voice Data to Effects (Left)
s8 SndWetL;
// Voice Data to Effects (Right)
s8 SndWetR;
// Interrupt Enable
s8 IRQEnable;
// DMA related?
s8 DMABits;
// Effect Enable
s8 FxEnable;
// Noise Clock
s8 NoiseClk;
// AutoDMA Status
u16 AutoDMACtrl;
// DMA Interrupt Counter
s32 DMAICounter;
// Mute
s8 Mute;
// Input Buffer
u32 InputDataLeft;
u32 InputPos;
u32 InputDataProgress;
u8 AdmaInProgress;
// Reverb
V_Reverb Revb;
u32 EffectsStartA;
u32 EffectsEndA;
u32 ReverbX;
// Last Transfer Size
u32 lastsize;
// Registers
V_CoreRegs Regs;
u8 InitDelay;
u8 CoreEnabled;
u8 AttrBit0;
u8 AttrBit4;
u8 AttrBit5;
u16*DMAPtr;
u32 MADR;
u32 TADR;
s16 ADMATempBuffer[0x1000];
u32 ADMAPV;
u32 ADMAPL;
u32 ADMAPR;
s32 AutoDMAPeak;
} V_Core;
extern V_Core Cores[2];
extern V_SPDIF Spdif;
// Output Buffer Writing Position (the same for all data);
extern s16 OutPos;
// Input Buffer Reading Position (the same for all data);
extern s16 InputPos;
// SPU Mixing Cycles ("Ticks mixed" counter)
extern u32 Cycles;
extern u8 InpBuff;
// 1b0 "hack"
extern u32 Num;
#endif // DEFS_H_INCLUDED //

16
plugins/spu2ghz/dialogs.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include "resource.h"
#include <commctrl.h>
#define SET_CHECK(idc,value) SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,((value)==0)?BST_UNCHECKED:BST_CHECKED,0)
#define HANDLE_CHECK(idc,hvar) case idc: hvar=hvar?0:1; SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,(hvar==1)?BST_CHECKED:BST_UNCHECKED,0); break
#define HANDLE_CHECKNB(idc,hvar)case idc: hvar=hvar?0:1; SendMessage(GetDlgItem(hWnd,idc),BM_SETCHECK,(hvar==1)?BST_CHECKED:BST_UNCHECKED,0)
#define ENABLE_CONTROL(idc,value) EnableWindow(GetDlgItem(hWnd,idc),value)
#define INIT_SLIDER(idc,minrange,maxrange,tickfreq,pagesize,linesize) \
SendMessage(GetDlgItem(hWnd,idc),TBM_SETRANGEMIN,FALSE,minrange); \
SendMessage(GetDlgItem(hWnd,idc),TBM_SETRANGEMAX,FALSE,maxrange); \
SendMessage(GetDlgItem(hWnd,idc),TBM_SETTICFREQ,tickfreq,0); \
SendMessage(GetDlgItem(hWnd,idc),TBM_SETPAGESIZE,0,pagesize); \
SendMessage(GetDlgItem(hWnd,idc),TBM_SETLINESIZE,0,linesize)

350
plugins/spu2ghz/dma.cpp Normal file
View File

@ -0,0 +1,350 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#include "spu2.h"
extern u8 callirq;
FILE *DMA4LogFile=0;
FILE *DMA7LogFile=0;
FILE *ADMA4LogFile=0;
FILE *ADMA7LogFile=0;
FILE *ADMAOutLogFile=0;
FILE *REGWRTLogFile[2]={0,0};
int packcount=0;
u16* MBASE[2] = {0,0};
u16* DMABaseAddr;
void DMALogOpen() {
if(!DMALog) return;
DMA4LogFile=fopen(DMA4LogFileName,"wb");
DMA7LogFile=fopen(DMA7LogFileName,"wb");
ADMA4LogFile=fopen("logs/adma4.raw","wb");
ADMA7LogFile=fopen("logs/adma7.raw","wb");
ADMAOutLogFile=fopen("logs/admaOut.raw","wb");
//REGWRTLogFile[0]=fopen("logs/RegWrite0.raw","wb");
//REGWRTLogFile[1]=fopen("logs/RegWrite1.raw","wb");
}
void DMA4LogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return;
if (!DMA4LogFile) return;
fwrite(lpData,ulSize,1,DMA4LogFile);
}
void DMA7LogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return;
if (!DMA7LogFile) return;
fwrite(lpData,ulSize,1,DMA7LogFile);
}
void ADMA4LogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return;
if (!ADMA4LogFile) return;
fwrite(lpData,ulSize,1,ADMA4LogFile);
}
void ADMA7LogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return;
if (!ADMA7LogFile) return;
fwrite(lpData,ulSize,1,ADMA7LogFile);
}
void ADMAOutLogWrite(void *lpData, u32 ulSize) {
if(!DMALog) return;
if (!ADMAOutLogFile) return;
fwrite(lpData,ulSize,1,ADMAOutLogFile);
}
void RegWriteLog(u32 core,u16 value)
{
if(!DMALog) return;
if (!REGWRTLogFile[core]) return;
fwrite(&value,2,1,REGWRTLogFile[core]);
}
void DMALogClose() {
if(!DMALog) return;
if (DMA4LogFile) fclose(DMA4LogFile);
if (DMA7LogFile) fclose(DMA7LogFile);
if (REGWRTLogFile[0]) fclose(REGWRTLogFile[0]);
if (REGWRTLogFile[1]) fclose(REGWRTLogFile[1]);
if (ADMA4LogFile) fclose(ADMA4LogFile);
if (ADMA7LogFile) fclose(ADMA7LogFile);
if (ADMAOutLogFile) fclose(ADMAOutLogFile);
}
u16 DmaRead(u32 core) {
u16 ret;
ret=spu2Mu16(Cores[core].TDA);
Cores[core].TDA++;
Cores[core].TDA&=0xfffff;
return ret;
}
void DmaWrite(u32 core, u16 value) {
spu2Mu16(Cores[core].TSA)=value;
Cores[core].TSA++;
Cores[core].TSA&=0xfffff;
}
void AutoDMAReadBuffer(int core, int mode) //mode: 0= split stereo; 1 = do not split stereo
{
int spos=((Cores[core].InputPos+0xff)&0x100); //starting position of the free buffer
if(core==0)
ADMA4LogWrite(Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400);
else
ADMA7LogWrite(Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400);
if(mode)
{
//hacky :p
memcpy((Cores[core].ADMATempBuffer+(spos<<1)),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x400);
Cores[core].MADR+=0x400;
Cores[core].InputDataLeft-=0x200;
Cores[core].InputDataProgress+=0x200;
}
else
{
memcpy((Cores[core].ADMATempBuffer+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200);
//memcpy((spu2mem+0x2000+(core<<10)+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200);
Cores[core].MADR+=0x200;
Cores[core].InputDataLeft-=0x100;
Cores[core].InputDataProgress+=0x100;
memcpy((Cores[core].ADMATempBuffer+spos+0x200),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200);
//memcpy((spu2mem+0x2200+(core<<10)+spos),Cores[core].DMAPtr+Cores[core].InputDataProgress,0x200);
Cores[core].MADR+=0x200;
Cores[core].InputDataLeft-=0x100;
Cores[core].InputDataProgress+=0x100;
}
// See ReadInput at mixer.cpp for explanation on the commented out lines
//
}
void StartADMAWrite(int core,u16 *pMem, u32 sz)
{
int size=(sz)&(~511);
if(MsgAutoDMA) ConLog(" * SPU2: DMA%c AutoDMA Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff);
Cores[core].InputDataProgress=0;
if((Cores[core].AutoDMACtrl&(core+1))==0)
{
Cores[core].TSA=0x2000+(core<<10);
Cores[core].DMAICounter=size;
}
else if(size>=512)
{
Cores[core].InputDataLeft=size;
if(Cores[core].AdmaInProgress==0)
{
#ifdef PCM24_S1_INTERLEAVE
if((core==1)&&((PlayMode&8)==8))
{
AutoDMAReadBuffer(core,1);
}
else
{
AutoDMAReadBuffer(core,0);
}
#else
if(((PlayMode&4)==4)&&(core==0))
Cores[0].InputPos=0;
AutoDMAReadBuffer(core,0);
#endif
if(size==512)
Cores[core].DMAICounter=size;
}
Cores[core].AdmaInProgress=1;
}
else
{
Cores[core].InputDataLeft=0;
Cores[core].DMAICounter=1;
}
Cores[core].TADR=Cores[core].MADR+(size<<1);
}
void DoDMAWrite(int core,u16 *pMem,u32 size)
{
u32 i;
u32 pa = ((u32)pMem)&7;
u32 pm = Cores[core].TSA&0x7;
if(pa || pm)
{
printf("* Missaligned addr in DMA write!\n");
}
if(core==0)
DMA4LogWrite(pMem,size<<1);
else
DMA7LogWrite(pMem,size<<1);
if(MsgDMA) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff);
Cores[core].TDA=Cores[core].TSA;
for (i=0;i<size;i++) {
spu2Mu16(Cores[core].TDA)=pMem[i];
Cores[core].TDA++;
Cores[core].TDA&=0xfffff;
}
i=Cores[core].TSA;
Cores[core].TDA=Cores[core].TSA+size;
if((Cores[core].TDA>0xFFFFF)||((Cores[core].TDA>=Cores[core].IRQA)&&(i<=Cores[core].IRQA))) {
if(Cores[core].IRQEnable)
{
Spdif.Info=4<<core;
SetIrqCall();
}
}
Cores[core].TSA=Cores[core].TDA&0xFFFF0;
Cores[core].DMAICounter=size;
Cores[core].TADR=Cores[core].MADR+(size<<1);
}
void SPU2readDMA(int core, u16* pMem, u32 size)
{
ENTER_CS(&threadSync);
if(hasPtr) TimeUpdate(*cPtr,1);
u32 i;
Cores[core].TSA&=~7;
Cores[core].TDA=Cores[core].TSA;
for (i=0;i<size;i++)
pMem[i]=DmaRead(core);
i=Cores[core].TSA;
Cores[core].TDA=Cores[core].TSA+size+0x1f;
Cores[core].TSA=Cores[core].TDA&0xFFFFF;
if((Cores[core].TDA>0xFFFFF)||((Cores[core].TSA<=Cores[core].IRQA)&&(i>=Cores[core].IRQA))) {
if(Cores[core].IRQEnable)
{
Spdif.Info=4<<core;
SetIrqCall();
}
}
Cores[core].DMAICounter=size;
Cores[core].Regs.STATX &= ~0x80;
//Cores[core].Regs.ATTR |= 0x30;
Cores[core].TADR=Cores[core].MADR+(size<<1);
LEAVE_CS(&threadSync);
}
void SPU2writeDMA(int core, u16* pMem, u32 size)
{
ENTER_CS(&threadSync);
if(hasPtr) TimeUpdate(*cPtr,1);
Cores[core].DMAPtr=pMem;
if(size<2) {
//if(dma7callback) dma7callback();
Cores[core].Regs.STATX &= ~0x80;
//Cores[core].Regs.ATTR |= 0x30;
Cores[core].DMAICounter=1;
LEAVE_CS(&threadSync);
return;
}
Cores[core].lastsize=size;
Cores[core].TSA&=~7;
bool adma_enable = ((Cores[core].AutoDMACtrl&(core+1))==(core+1));
if(adma_enable)
{
Cores[core].TSA&=0x1fff;
StartADMAWrite(core,pMem,size);
}
else
{
DoDMAWrite(core,pMem,size);
}
Cores[core].Regs.STATX &= ~0x80;
//Cores[core].Regs.ATTR |= 0x30;
LEAVE_CS(&threadSync);
}
u32 CALLBACK SPU2ReadMemAddr(int core)
{
return Cores[core].MADR;
}
void CALLBACK SPU2WriteMemAddr(int core,u32 value)
{
Cores[core].MADR=value;
}
void CALLBACK SPU2setDMABaseAddr(uptr baseaddr)
{
DMABaseAddr = (u16*)baseaddr;
}
void CALLBACK SPU2readDMA4Mem(u16 *pMem, u32 size) { //size now in 16bit units
FileLog("[%10d] SPU2 readDMA4Mem size %x\n",Cycles, size<<1);
SPU2readDMA(0,pMem,size);
}
void CALLBACK SPU2writeDMA4Mem(u16* pMem, u32 size) { //size now in 16bit units
FileLog("[%10d] SPU2 writeDMA4Mem size %x at address %x\n",Cycles, size<<1, Cores[0].TSA);
#ifdef S2R_ENABLE
if(!replay_mode)
s2r_writedma4(Cycles,pMem,size);
#endif
SPU2writeDMA(0,pMem,size);
}
void CALLBACK SPU2interruptDMA4() {
FileLog("[%10d] SPU2 interruptDMA4\n",Cycles);
Cores[0].Regs.STATX |= 0x80;
//Cores[0].Regs.ATTR &= ~0x30;
}
void CALLBACK SPU2readDMA7Mem(u16* pMem, u32 size) {
FileLog("[%10d] SPU2 readDMA7Mem size %x\n",Cycles, size<<1);
SPU2readDMA(1,pMem,size);
}
void CALLBACK SPU2writeDMA7Mem(u16* pMem, u32 size) {
FileLog("[%10d] SPU2 writeDMA7Mem size %x at address %x\n",Cycles, size<<1, Cores[1].TSA);
#ifdef S2R_ENABLE
if(!replay_mode)
s2r_writedma7(Cycles,pMem,size);
#endif
SPU2writeDMA(1,pMem,size);
}
void CALLBACK SPU2interruptDMA7() {
FileLog("[%10d] SPU2 interruptDMA7\n",Cycles);
Cores[1].Regs.STATX |= 0x80;
//Cores[1].Regs.ATTR &= ~0x30;
}

31
plugins/spu2ghz/dma.h Normal file
View File

@ -0,0 +1,31 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#ifndef DMA_H_INCLUDED
#define DMA_H_INCLUDED
void DMALogOpen();
void DMA4LogWrite(void *lpData, u32 ulSize);
void DMA7LogWrite(void *lpData, u32 ulSize);
void DMALogClose();
void DmaWrite(u32 core, u16 data);
u16 DmaRead(u32 core);
void AutoDMAReadBuffer(int core, int mode);
#endif // DMA_H_INCLUDED //

View File

@ -0,0 +1,554 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#define _WIN32_DCOM
#include "spu2.h"
#include "dialogs.h"
#include <initguid.h>
#include <windows.h>
#include <dsound.h>
#include <strsafe.h>
#include <shellapi.h>
#include <mmsystem.h>
#include <conio.h>
#include <assert.h>
#include <Mmreg.h>
#include <ks.h>
#include <KSMEDIA.H>
#include "lowpass.h"
#define ENABLE_DPLII
struct ds_device_data {
char name[256];
GUID guid;
bool hasGuid;
} extern devices[];
extern int ndevs;
extern GUID DevGuid;
extern bool haveGuid;
extern HRESULT GUIDFromString(const char *str, LPGUID guid);
class DSound51: public SndOutModule
{
private:
# define PI 3.14159265f
# define BufferSize (CurBufferSize*6)
# define BufferSizeBytes (BufferSize<<1)
# define TBufferSize (BufferSize*CurBufferCount)
s32* tbuffer;
FILE *voicelog;
int channel;
bool dsound_running;
HANDLE thread;
DWORD tid;
#define MAX_BUFFER_COUNT 3
IDirectSound8* dsound;
IDirectSoundBuffer8* buffer;
IDirectSoundNotify8* buffer_notify;
HANDLE buffer_events[MAX_BUFFER_COUNT];
WAVEFORMATEXTENSIBLE wfx;
SndBuffer *buff;
s32 LAccum;
s32 RAccum;
s32 ANum;
s32 LBuff[128];
s32 RBuff[128];
LPF_data lpf_l;
LPF_data lpf_r;
void Convert(s16 *obuffer, s32 ValL, s32 ValR)
{
static u8 bufdone=1;
static s32 Gfl=0,Gfr=0;
static s32 spdif_data[6];
static s32 LMax=0,RMax=0;
if(PlayMode&4)
{
spdif_get_samples(spdif_data);
}
else
{
spdif_data[0]=0;
spdif_data[1]=0;
spdif_data[2]=0;
spdif_data[3]=0;
spdif_data[4]=0;
spdif_data[5]=0;
}
#ifdef ENABLE_DPLII
#ifdef USE_AVERAGING
LAccum+=abs(ValL);
RAccum+=abs(ValR);
ANum++;
if(ANum>=512)
{
LMax=0;RMax=0;
LAccum/=ANum;
RAccum/=ANum;
ANum=0;
for(int i=0;i<127;i++)
{
LMax+=LBuff[i];
RMax+=RBuff[i];
LBuff[i]=LBuff[i+1];
RBuff[i]=RBuff[i+1];
}
LBuff[127]=LAccum;
RBuff[127]=RAccum;
LMax+=LAccum;
RMax+=RAccum;
s32 TL = (LMax>>15)+1;
s32 TR = (RMax>>15)+1;
Gfl=(RMax)/(TL);
Gfr=(LMax)/(TR);
if(Gfl>255) Gfl=255;
if(Gfr>255) Gfr=255;
}
#else
if((ValL>>8)>LMax) LMax = (ValL>>8);
if(-(ValL>>8)>LMax) LMax = -(ValL>>8);
if((ValR>>8)>RMax) RMax = (ValR>>8);
if(-(ValR>>8)>RMax) RMax = -(ValR>>8);
ANum++;
if(ANum>=128)
{
ANum=0;
LAccum = (LAccum * 224 + LMax * 32)>>8;
RAccum = (RAccum * 224 + RMax * 32)>>8;
LMax=0;
RMax=0;
if(LAccum<1) LAccum=1;
if(RAccum<1) RAccum=1;
Gfl=(RAccum)*255/(LAccum);
Gfr=(LAccum)*255/(RAccum);
int gMax = max(Gfl,Gfr);
Gfl=Gfl*255/gMax;
Gfr=Gfr*255/gMax;
if(Gfl>255) Gfl=255;
if(Gfr>255) Gfr=255;
if(Gfl<1) Gfl=1;
if(Gfr<1) Gfr=1;
}
#endif
s32 L,R,C,LFE,SL,SR,LL,LR;
extern double pow_2_31;
LL = (s32)(LPF(&lpf_l,(ValL>>4)/pow_2_31)*pow_2_31);
LR = (s32)(LPF(&lpf_r,(ValR>>4)/pow_2_31)*pow_2_31);
LFE = (LL + LR)>>4;
C=(ValL+ValR)>>1; //16.8
ValL-=C;//16.8
ValR-=C;//16.8
L=ValL>>8; //16.0
R=ValR>>8; //16.0
C=C>>8; //16.0
s32 VL=(ValL>>4) * Gfl; //16.12
s32 VR=(ValR>>4) * Gfr;
SL=(VL/209 - VR/148)>>4; //16.0 (?)
SR=(VL/148 - VR/209)>>4; //16.0 (?)
// increase surround stereo separation
int SC = (SL+SR)>>1; //16.0
int SLd = SL - SC; //16.0
int SRd = SL - SC; //16.0
SL = (SLd * 209 + SC * 148)>>8; //16.0
SR = (SRd * 209 + SC * 148)>>8; //16.0
obuffer[0]=spdif_data[0] + (((L * GainL ) + (C * AddCLR))>>8);
obuffer[1]=spdif_data[1] + (((R * GainR ) + (C * AddCLR))>>8);
obuffer[2]=spdif_data[2] + (((C * GainC ))>>8);
obuffer[3]=spdif_data[3] + (((LFE * GainLFE))>>8);
obuffer[4]=spdif_data[4] + (((SL * GainSL ))>>8);
obuffer[5]=spdif_data[5] + (((SR * GainSR ))>>8);
#else
obuffer[0]=spdif_data[0]+(ValL>>8);
obuffer[1]=spdif_data[1]+(ValR>>8);
obuffer[2]=spdif_data[2];
obuffer[3]=spdif_data[3];
obuffer[4]=spdif_data[4];
obuffer[5]=spdif_data[5];
#endif
}
# define STRFY(x) #x
# define verifyc(x) if(Verifyc(x,STRFY(x))) return -1;
static DWORD CALLBACK RThread(DSound51*obj)
{
return obj->Thread();
}
int __forceinline Verifyc(HRESULT hr,const char* fn)
{
if(FAILED(hr))
{
SysMessage("ERROR: Call to %s Failed.",fn);
return -1;
}
return 0;
}
DWORD Thread()
{
while( dsound_running )
{
u32 rv = WaitForMultipleObjects(MAX_BUFFER_COUNT,buffer_events,FALSE,400);
LPVOID p1,p2;
DWORD s1,s2;
for(int i=0;i<MAX_BUFFER_COUNT;i++)
{
if (rv==WAIT_OBJECT_0+i)
{
u32 poffset=BufferSizeBytes * i;
buff->ReadSamples(tbuffer,CurBufferSize*2);
verifyc(buffer->Lock(poffset,BufferSizeBytes,&p1,&s1,&p2,&s2,0));
s16 *t = (s16*)p1;
s32 *s = tbuffer;
for(int i=0;i<CurBufferSize;i++)
{
// DPL2 code here: inputs s[0] and s[1]. outputs t[0] to t[5]
Convert(t,s[0],s[1]);
t+=6;
s+=2;
}
verifyc(buffer->Unlock(p1,s1,p2,s2));
}
}
}
return 0;
}
public:
s32 Init(SndBuffer *sb)
{
if(CurBufferSize<1024) CurBufferSize=1024;
buff = sb;
//
// Initialize DSound
//
verifyc(DirectSoundCreate8(NULL,&dsound,NULL));
verifyc(dsound->SetCooperativeLevel(GetDesktopWindow(),DSSCL_PRIORITY));
IDirectSoundBuffer* buffer_;
DSBUFFERDESC desc;
// Set up WAV format structure.
memset(&wfx, 0, sizeof(WAVEFORMATEX));
wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfx.Format.nSamplesPerSec = SampleRate;
wfx.Format.nChannels=6;
wfx.Format.wBitsPerSample = 16;
wfx.Format.nBlockAlign = wfx.Format.nChannels*wfx.Format.wBitsPerSample/8;
wfx.Format.nAvgBytesPerSec = SampleRate * wfx.Format.nBlockAlign;
wfx.Format.cbSize=22;
wfx.Samples.wValidBitsPerSample=0;
wfx.dwChannelMask=SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT;
wfx.SubFormat=KSDATAFORMAT_SUBTYPE_PCM;
verifyc(dsound->SetSpeakerConfig(DSSPEAKER_5POINT1));
// Set up DSBUFFERDESC structure.
memset(&desc, 0, sizeof(DSBUFFERDESC));
desc.dwSize = sizeof(DSBUFFERDESC);
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
desc.dwBufferBytes = BufferSizeBytes * MAX_BUFFER_COUNT;
desc.lpwfxFormat = &wfx.Format;
desc.dwFlags |=DSBCAPS_LOCSOFTWARE;
desc.dwFlags|=DSBCAPS_GLOBALFOCUS;
verifyc(dsound->CreateSoundBuffer(&desc,&buffer_,0));
verifyc(buffer_->QueryInterface(IID_IDirectSoundBuffer8,(void**)&buffer));
buffer_->Release();
verifyc(buffer->QueryInterface(IID_IDirectSoundNotify8,(void**)&buffer_notify));
DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT];
for(int i=0;i<MAX_BUFFER_COUNT;i++)
{
buffer_events[i]=CreateEvent(NULL,FALSE,FALSE,NULL);
not[i].dwOffset=(wfx.Format.nBlockAlign*10 + BufferSizeBytes*(i+1))%desc.dwBufferBytes;
not[i].hEventNotify=buffer_events[i];
}
buffer_notify->SetNotificationPositions(MAX_BUFFER_COUNT,not);
LPVOID p1=0,p2=0;
DWORD s1=0,s2=0;
verifyc(buffer->Lock(0,desc.dwBufferBytes,&p1,&s1,&p2,&s2,0));
assert(p2==0);
memset(p1,0,s1);
verifyc(buffer->Unlock(p1,s1,p2,s2));
LPF_init(&lpf_l,LowpassLFE,SampleRate);
LPF_init(&lpf_r,LowpassLFE,SampleRate);
//Play the buffer !
verifyc(buffer->Play(0,0,DSBPLAY_LOOPING));
tbuffer = new s32[BufferSize];
// Start Thread
dsound_running=true;
thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RThread,this,0,&tid);
SetThreadPriority(thread,THREAD_PRIORITY_TIME_CRITICAL);
return 0;
}
void Close()
{
// Stop Thread
fprintf(stderr," * SPU2: Waiting for DSound thread to finish...");
dsound_running=false;
WaitForSingleObject(thread,INFINITE);
CloseHandle(thread);
fprintf(stderr," Done.\n");
//
// Clean up
//
buffer->Stop();
for(int i=0;i<MAX_BUFFER_COUNT;i++)
CloseHandle(buffer_events[i]);
buffer_notify->Release();
buffer->Release();
dsound->Release();
delete tbuffer;
}
private:
static BOOL CALLBACK DSEnumCallback( LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext )
{
//strcpy(devices[ndevs].name,lpcstrDescription);
_snprintf_s(devices[ndevs].name,256,255,"%s",lpcstrDescription);
if(lpGuid)
{
devices[ndevs].guid=*lpGuid;
devices[ndevs].hasGuid = true;
}
else
{
devices[ndevs].hasGuid = false;
}
ndevs++;
if(ndevs<32) return TRUE;
return FALSE;
}
static BOOL DoHandleScrollMessage(WPARAM wParam, LPARAM lParam, int vmin, int vmax, HWND hwndDisplay)
{
int wmId = LOWORD(wParam);
int wmEvent = HIWORD(wParam);
static char temp[1024];
switch(wmId) {
//case TB_ENDTRACK:
//case TB_THUMBPOSITION:
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
wmEvent=(int)SendMessage((HWND)lParam,TBM_GETPOS,0,0);
case TB_THUMBTRACK:
if(wmEvent<vmin) wmEvent=vmin;
if(wmEvent>vmax) wmEvent=vmax;
SendMessage((HWND)lParam,TBM_SETPOS,TRUE,wmEvent);
sprintf(temp,"%d",vmax-wmEvent);
SetWindowText(hwndDisplay,temp);
break;
default:
return FALSE;
}
return TRUE;
}
#define HANDLE_SCROLL_MESSAGE(idc,vmin,vmax,idcDisplay) \
if((HWND)lParam == GetDlgItem(hWnd,idc)) return DoHandleScrollMessage(wParam,lParam,vmin,vmax,GetDlgItem(hWnd,idcDisplay))
static BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
int wmId,wmEvent;
int tSel=0;
switch(uMsg)
{
case WM_INITDIALOG:
haveGuid = ! FAILED(GUIDFromString(DSoundDevice,&DevGuid));
SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_RESETCONTENT,0,0);
ndevs=0;
DirectSoundEnumerate(DSEnumCallback,NULL);
tSel=-1;
for(int i=0;i<ndevs;i++)
{
SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_ADDSTRING,0,(LPARAM)devices[i].name);
if(haveGuid && IsEqualGUID(devices[i].guid,DevGuid))
{
tSel=i;
}
}
if(tSel>=0)
{
SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_SETCURSEL,tSel,0);
}
INIT_SLIDER(IDC_SLIDER1,0,512,64,16,8);
INIT_SLIDER(IDC_SLIDER2,0,512,64,16,8);
INIT_SLIDER(IDC_SLIDER3,0,512,64,16,8);
INIT_SLIDER(IDC_SLIDER4,0,512,64,16,8);
INIT_SLIDER(IDC_SLIDER5,0,512,64,16,8);
INIT_SLIDER(IDC_SLIDER6,0,512,64,16,8);
INIT_SLIDER(IDC_SLIDER7,0,512,64,16,8);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDOK:
{
int i = (int)SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_GETCURSEL,0,0);
if(!devices[i].hasGuid)
{
DSoundDevice[0]=0; // clear device name to ""
}
else
{
sprintf_s(DSoundDevice,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
devices[i].guid.Data1,
devices[i].guid.Data2,
devices[i].guid.Data3,
devices[i].guid.Data4[0],
devices[i].guid.Data4[1],
devices[i].guid.Data4[2],
devices[i].guid.Data4[3],
devices[i].guid.Data4[4],
devices[i].guid.Data4[5],
devices[i].guid.Data4[6],
devices[i].guid.Data4[7]
);
}
}
EndDialog(hWnd,0);
break;
case IDCANCEL:
EndDialog(hWnd,0);
break;
default:
return FALSE;
}
break;
case WM_VSCROLL:
HANDLE_SCROLL_MESSAGE(IDC_SLIDER1,0,512,IDC_EDIT1);
HANDLE_SCROLL_MESSAGE(IDC_SLIDER2,0,512,IDC_EDIT2);
HANDLE_SCROLL_MESSAGE(IDC_SLIDER3,0,512,IDC_EDIT3);
HANDLE_SCROLL_MESSAGE(IDC_SLIDER4,0,512,IDC_EDIT4);
HANDLE_SCROLL_MESSAGE(IDC_SLIDER5,0,512,IDC_EDIT5);
HANDLE_SCROLL_MESSAGE(IDC_SLIDER6,0,512,IDC_EDIT6);
HANDLE_SCROLL_MESSAGE(IDC_SLIDER7,0,512,IDC_EDIT7);
default:
return FALSE;
}
return TRUE;
}
public:
virtual void Configure(HWND parent)
{
INT_PTR ret;
ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DSOUND51),GetActiveWindow(),(DLGPROC)ConfigProc,1);
if(ret==-1)
{
MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0);
return;
}
}
s32 Test()
{
return 0;
}
bool Is51Out() { return true; }
} DS51;
SndOutModule *DSound51Out=&DS51;

View File

@ -0,0 +1,382 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#define _WIN32_DCOM
#include "spu2.h"
#include "dialogs.h"
#include <initguid.h>
#include <windows.h>
#include <dsound.h>
#include <strsafe.h>
#include <shellapi.h>
#include <mmsystem.h>
#include <conio.h>
#include <assert.h>
struct ds_device_data {
char name[256];
GUID guid;
bool hasGuid;
} devices[32];
int ndevs;
GUID DevGuid;
bool haveGuid;
HRESULT GUIDFromString(const char *str, LPGUID guid)
{
// "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
struct T{ // this is a hack because for some reason sscanf writes too much :/
GUID g;
int k;
} t;
int r = sscanf_s(str,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
&t.g.Data1,
&t.g.Data2,
&t.g.Data3,
&t.g.Data4[0],
&t.g.Data4[1],
&t.g.Data4[2],
&t.g.Data4[3],
&t.g.Data4[4],
&t.g.Data4[5],
&t.g.Data4[6],
&t.g.Data4[7]
);
if(r!=11) return -1;
*guid = t.g;
return 0;
}
class DSound: public SndOutModule
{
private:
# define PI 3.14159265f
# define BufferSize (CurBufferSize<<1)
# define BufferSizeBytes (BufferSize<<1)
# define TBufferSize (BufferSize*CurBufferCount)
FILE *voicelog;
int channel;
bool dsound_running;
HANDLE thread;
DWORD tid;
# define MAX_BUFFER_COUNT 5
IDirectSound8* dsound;
IDirectSoundBuffer8* buffer;
IDirectSoundNotify8* buffer_notify;
HANDLE buffer_events[MAX_BUFFER_COUNT];
WAVEFORMATEX wfx;
HANDLE waitEvent;
SndBuffer *buff;
s32 *tbuffer;
# define STRFY(x) #x
# define verifyc(x) if(Verifyc(x,STRFY(x))) return -1;
int __forceinline Verifyc(HRESULT hr,const char* fn)
{
if(FAILED(hr))
{
SysMessage("ERROR: Call to %s Failed.",fn);
return -1;
}
return 0;
}
static DWORD CALLBACK RThread(DSound*obj)
{
return obj->Thread();
}
DWORD CALLBACK Thread()
{
while( dsound_running )
{
u32 rv = WaitForMultipleObjects(MAX_BUFFER_COUNT,buffer_events,FALSE,400);
LPVOID p1,p2;
DWORD s1,s2;
for(int i=0;i<MAX_BUFFER_COUNT;i++)
{
if (rv==WAIT_OBJECT_0+i)
{
u32 poffset=BufferSizeBytes * i;
buff->ReadSamples(tbuffer,BufferSize);
verifyc(buffer->Lock(poffset,BufferSizeBytes,&p1,&s1,&p2,&s2,0));
s16 *t = (s16*)p1;
s32 *s = (s32*)tbuffer;
for(int i=0;i<BufferSize;i++)
{
*(t++) = (s16)((*(s++))>>8);
}
verifyc(buffer->Unlock(p1,s1,p2,s2));
}
}
}
return 0;
}
public:
s32 Init(SndBuffer *sb)
{
buff = sb;
//
// Initialize DSound
//
GUID cGuid;
if((strlen(DSoundDevice)>0)&&(!FAILED(GUIDFromString(DSoundDevice,&cGuid))))
{
verifyc(DirectSoundCreate8(&cGuid,&dsound,NULL));
}
else
{
verifyc(DirectSoundCreate8(NULL,&dsound,NULL));
}
verifyc(dsound->SetCooperativeLevel(GetDesktopWindow(),DSSCL_PRIORITY));
IDirectSoundBuffer* buffer_;
DSBUFFERDESC desc;
// Set up WAV format structure.
memset(&wfx, 0, sizeof(WAVEFORMATEX));
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nSamplesPerSec = SampleRate;
wfx.nChannels=2;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = 2*2;
wfx.nAvgBytesPerSec = SampleRate * 2 * 2;
wfx.cbSize=0;
// Set up DSBUFFERDESC structure.
memset(&desc, 0, sizeof(DSBUFFERDESC));
desc.dwSize = sizeof(DSBUFFERDESC);
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
desc.dwBufferBytes = BufferSizeBytes * MAX_BUFFER_COUNT;
desc.lpwfxFormat = &wfx;
desc.dwFlags |=DSBCAPS_LOCSOFTWARE;
desc.dwFlags|=DSBCAPS_GLOBALFOCUS;
verifyc(dsound->CreateSoundBuffer(&desc,&buffer_,0));
verifyc(buffer_->QueryInterface(IID_IDirectSoundBuffer8,(void**)&buffer));
buffer_->Release();
verifyc(buffer->QueryInterface(IID_IDirectSoundNotify8,(void**)&buffer_notify));
DSBPOSITIONNOTIFY not[MAX_BUFFER_COUNT];
for(int i=0;i<MAX_BUFFER_COUNT;i++)
{
buffer_events[i]=CreateEvent(NULL,FALSE,FALSE,NULL);
not[i].dwOffset=(wfx.nBlockAlign*10 + BufferSizeBytes*(i+1))%desc.dwBufferBytes;
not[i].hEventNotify=buffer_events[i];
}
buffer_notify->SetNotificationPositions(MAX_BUFFER_COUNT,not);
LPVOID p1=0,p2=0;
DWORD s1=0,s2=0;
verifyc(buffer->Lock(0,desc.dwBufferBytes,&p1,&s1,&p2,&s2,0));
assert(p2==0);
memset(p1,0,s1);
verifyc(buffer->Unlock(p1,s1,p2,s2));
//Play the buffer !
verifyc(buffer->Play(0,0,DSBPLAY_LOOPING));
tbuffer = new s32[BufferSize];
// Start Thread
dsound_running=true;
thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RThread,this,0,&tid);
SetThreadPriority(thread,THREAD_PRIORITY_TIME_CRITICAL);
return 0;
}
void Close()
{
// Stop Thread
fprintf(stderr," * SPU2: Waiting for DSound thread to finish...");
dsound_running=false;
WaitForSingleObject(thread,INFINITE);
CloseHandle(thread);
fprintf(stderr," Done.\n");
//
// Clean up
//
buffer->Stop();
for(int i=0;i<MAX_BUFFER_COUNT;i++)
CloseHandle(buffer_events[i]);
buffer_notify->Release();
buffer->Release();
dsound->Release();
delete tbuffer;
}
private:
static BOOL CALLBACK DSEnumCallback( LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext )
{
//strcpy(devices[ndevs].name,lpcstrDescription);
_snprintf_s(devices[ndevs].name,256,255,"%s",lpcstrDescription);
if(lpGuid)
{
devices[ndevs].guid=*lpGuid;
devices[ndevs].hasGuid = true;
}
else
{
devices[ndevs].hasGuid = false;
}
ndevs++;
if(ndevs<32) return TRUE;
return FALSE;
}
static BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
int wmId,wmEvent;
int tSel=0;
switch(uMsg)
{
case WM_INITDIALOG:
haveGuid = ! FAILED(GUIDFromString(DSoundDevice,&DevGuid));
SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_RESETCONTENT,0,0);
ndevs=0;
DirectSoundEnumerate(DSEnumCallback,NULL);
tSel=-1;
for(int i=0;i<ndevs;i++)
{
SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_ADDSTRING,0,(LPARAM)devices[i].name);
if(haveGuid && IsEqualGUID(devices[i].guid,DevGuid))
{
tSel=i;
}
}
if(tSel>=0)
{
SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_SETCURSEL,tSel,0);
}
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDOK:
{
int i = (int)SendMessage(GetDlgItem(hWnd,IDC_DS_DEVICE),CB_GETCURSEL,0,0);
if(!devices[i].hasGuid)
{
DSoundDevice[0]=0; // clear device name to ""
}
else
{
sprintf_s(DSoundDevice,256,"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
devices[i].guid.Data1,
devices[i].guid.Data2,
devices[i].guid.Data3,
devices[i].guid.Data4[0],
devices[i].guid.Data4[1],
devices[i].guid.Data4[2],
devices[i].guid.Data4[3],
devices[i].guid.Data4[4],
devices[i].guid.Data4[5],
devices[i].guid.Data4[6],
devices[i].guid.Data4[7]
);
}
}
EndDialog(hWnd,0);
break;
case IDCANCEL:
EndDialog(hWnd,0);
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
public:
virtual void Configure(HWND parent)
{
INT_PTR ret;
ret=DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DSOUND),GetActiveWindow(),(DLGPROC)ConfigProc,1);
if(ret==-1)
{
MessageBoxEx(GetActiveWindow(),"Error Opening the config dialog.","OMG ERROR!",MB_OK,0);
return;
}
}
virtual bool Is51Out() { return false; }
s32 Test()
{
return 0;
}
} DS;
SndOutModule *DSoundOut=&DS;

174
plugins/spu2ghz/dsp.cpp Normal file
View File

@ -0,0 +1,174 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#include "spu2.h"
extern "C" {
#include "dsp.h"
typedef winampDSPHeader* (*pWinampDSPGetHeader2)();
}
HMODULE hLib = NULL;
pWinampDSPGetHeader2 pGetHeader = NULL;
winampDSPHeader* pHeader = NULL;
winampDSPModule* pModule = NULL;
HWND hTemp;
#define USE_A_THREAD
#ifdef USE_A_THREAD
HANDLE hUpdateThread;
DWORD UpdateThreadId;
bool running;
DWORD WINAPI DspUpdateThread(PVOID param);
#endif
s32 DspLoadLibrary(char *fileName, int modNum)
#ifdef USE_A_THREAD
{
if(!dspPluginEnabled) return -1;
running=true;
hUpdateThread = CreateThread(NULL,0,DspUpdateThread,NULL,0,&UpdateThreadId);
return (hUpdateThread==INVALID_HANDLE_VALUE);
}
s32 DspLoadLibrary2(char *fileName, int modNum)
#endif
{
if(!dspPluginEnabled) return -1;
hLib = LoadLibraryA(fileName);
if(!hLib)
{
return 1;
}
pGetHeader = (pWinampDSPGetHeader2)GetProcAddress(hLib,"winampDSPGetHeader2");
if(!pGetHeader)
{
FreeLibrary(hLib);
hLib=NULL;
return 1;
}
pHeader = pGetHeader();
pModule = pHeader->getModule(modNum);
if(!pModule)
{
pGetHeader=NULL;
pHeader=NULL;
FreeLibrary(hLib);
hLib=NULL;
return -1;
}
pModule->hDllInstance = hLib;
pModule->hwndParent=0;
pModule->Init(pModule);
return 0;
}
void DspCloseLibrary()
#ifdef USE_A_THREAD
{
if(!dspPluginEnabled) return ;
PostThreadMessage(UpdateThreadId,WM_QUIT,0,0);
running=false;
if(WaitForSingleObject(hUpdateThread,1000)==WAIT_TIMEOUT)
{
TerminateThread(hUpdateThread,1);
}
}
void DspCloseLibrary2()
#endif
{
if(!dspPluginEnabled) return ;
if(hLib)
{
pModule->Quit(pModule);
FreeLibrary(hLib);
}
pModule=NULL;
pHeader=NULL;
pGetHeader=NULL;
hLib=NULL;
}
int DspProcess(s16 *buffer, int samples)
{
if(!dspPluginEnabled) return samples;
if(hLib)
{
return pModule->ModifySamples(pModule,buffer,samples,16,2,SampleRate);
}
return samples;
}
void DspUpdate()
#ifdef USE_A_THREAD
{
}
DWORD WINAPI DspUpdateThread(PVOID param)
{
if(!dspPluginEnabled) return -1;
if(DspLoadLibrary2(dspPlugin,dspPluginModule))
return -1;
MSG msg;
while(running)
{
GetMessage(&msg,0,0,0);
if((msg.hwnd==NULL)&&(msg.message==WM_QUIT))
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
DspCloseLibrary2();
return 0;
}
#else
{
if(!dspPluginEnabled) return;
MSG msg;
while(PeekMessage(&msg,0,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#endif

56
plugins/spu2ghz/dsp.h Normal file
View File

@ -0,0 +1,56 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// DSP plugin interface
// notes:
// any window that remains in foreground should optimally pass unused
// keystrokes to the parent (winamp's) window, so that the user
// can still control it. As for storing configuration,
// Configuration data should be stored in <dll directory>\plugin.ini
// (look at the vis plugin for configuration code)
typedef struct winampDSPModule {
char *description; // description
HWND hwndParent; // parent window (filled in by calling app)
HINSTANCE hDllInstance; // instance handle to this DLL (filled in by calling app)
void (*Config)(struct winampDSPModule *this_mod); // configuration dialog (if needed)
int (*Init)(struct winampDSPModule *this_mod); // 0 on success, creates window, etc (if needed)
// modify waveform samples: returns number of samples to actually write
// (typically numsamples, but no more than twice numsamples, and no less than half numsamples)
// numsamples should always be at least 128. should, but I'm not sure
int (*ModifySamples)(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate);
void (*Quit)(struct winampDSPModule *this_mod); // called when unloading
void *userData; // user data, optional
} winampDSPModule;
typedef struct {
int version; // DSP_HDRVER
char *description; // description of library
winampDSPModule* (*getModule)(int); // module retrieval function
} winampDSPHeader;
// exported symbols
typedef winampDSPHeader* (*winampDSPGetHeaderType)();
// header version: 0x20 == 0.20 == winamp 2.0
#define DSP_HDRVER 0x20

View File

@ -0,0 +1,62 @@
/*
* a52.h
* Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of a52dec, a free ATSC A-52 stream decoder.
* See http://liba52.sourceforge.net/ for updates.
*
* a52dec 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.
*
* a52dec is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef A52_H
#define A52_H
#ifndef LIBA52_DOUBLE
typedef float sample_t;
#else
typedef double sample_t;
#endif
typedef struct a52_state_s a52_state_t;
#define A52_CHANNEL 0
#define A52_MONO 1
#define A52_STEREO 2
#define A52_3F 3
#define A52_2F1R 4
#define A52_3F1R 5
#define A52_2F2R 6
#define A52_3F2R 7
#define A52_CHANNEL1 8
#define A52_CHANNEL2 9
#define A52_DOLBY 10
#define A52_CHANNEL_MASK 15
#define A52_LFE 16
#define A52_ADJUST_LEVEL 32
a52_state_t * a52_init (uint32_t mm_accel);
sample_t * a52_samples (a52_state_t * state);
int a52_syncinfo (uint8_t * buf, int * flags,
int * sample_rate, int * bit_rate);
int a52_frame (a52_state_t * state, uint8_t * buf, int * flags,
sample_t * level, sample_t bias);
void a52_dynrng (a52_state_t * state,
sample_t (* call) (sample_t, void *), void * data);
int a52_block (a52_state_t * state);
void a52_free (a52_state_t * state);
#endif /* A52_H */

View File

@ -0,0 +1,120 @@
/*
* a52_internal.h
* Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of a52dec, a free ATSC A-52 stream decoder.
* See http://liba52.sourceforge.net/ for updates.
*
* a52dec 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.
*
* a52dec is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
typedef struct {
uint8_t bai; /* fine SNR offset, fast gain */
uint8_t deltbae; /* delta bit allocation exists */
int8_t deltba[50]; /* per-band delta bit allocation */
} ba_t;
typedef struct {
uint8_t exp[256]; /* decoded channel exponents */
int8_t bap[256]; /* derived channel bit allocation */
} expbap_t;
struct a52_state_s {
uint8_t fscod; /* sample rate */
uint8_t halfrate; /* halfrate factor */
uint8_t acmod; /* coded channels */
uint8_t lfeon; /* coded lfe channel */
sample_t clev; /* centre channel mix level */
sample_t slev; /* surround channels mix level */
int output; /* type of output */
sample_t level; /* output level */
sample_t bias; /* output bias */
int dynrnge; /* apply dynamic range */
sample_t dynrng; /* dynamic range */
void * dynrngdata; /* dynamic range callback funtion and data */
sample_t (* dynrngcall) (sample_t range, void * dynrngdata);
uint8_t chincpl; /* channel coupled */
uint8_t phsflginu; /* phase flags in use (stereo only) */
uint8_t cplstrtmant; /* coupling channel start mantissa */
uint8_t cplendmant; /* coupling channel end mantissa */
uint32_t cplbndstrc; /* coupling band structure */
sample_t cplco[5][18]; /* coupling coordinates */
/* derived information */
uint8_t cplstrtbnd; /* coupling start band (for bit allocation) */
uint8_t ncplbnd; /* number of coupling bands */
uint8_t rematflg; /* stereo rematrixing */
uint8_t endmant[5]; /* channel end mantissa */
uint16_t bai; /* bit allocation information */
uint32_t * buffer_start;
uint16_t lfsr_state; /* dither state */
uint32_t bits_left;
uint32_t current_word;
uint8_t csnroffst; /* coarse SNR offset */
ba_t cplba; /* coupling bit allocation parameters */
ba_t ba[5]; /* channel bit allocation parameters */
ba_t lfeba; /* lfe bit allocation parameters */
uint8_t cplfleak; /* coupling fast leak init */
uint8_t cplsleak; /* coupling slow leak init */
expbap_t cpl_expbap;
expbap_t fbw_expbap[5];
expbap_t lfe_expbap;
sample_t * samples;
int downmixed;
};
#define LEVEL_PLUS6DB 2.0
#define LEVEL_PLUS3DB 1.4142135623730951
#define LEVEL_3DB 0.7071067811865476
#define LEVEL_45DB 0.5946035575013605
#define LEVEL_6DB 0.5
#define EXP_REUSE (0)
#define EXP_D15 (1)
#define EXP_D25 (2)
#define EXP_D45 (3)
#define DELTA_BIT_REUSE (0)
#define DELTA_BIT_NEW (1)
#define DELTA_BIT_NONE (2)
#define DELTA_BIT_RESERVED (3)
void a52_bit_allocate (a52_state_t * state, ba_t * ba, int bndstart,
int start, int end, int fastleak, int slowleak,
expbap_t * expbap);
int a52_downmix_init (int input, int flags, sample_t * level,
sample_t clev, sample_t slev);
int a52_downmix_coeff (sample_t * coeff, int acmod, int output, sample_t level,
sample_t clev, sample_t slev);
void a52_downmix (sample_t * samples, int acmod, int output, sample_t bias,
sample_t clev, sample_t slev);
void a52_upmix (sample_t * samples, int acmod, int output);
void a52_imdct_init (uint32_t mm_accel);
void a52_imdct_256 (sample_t * data, sample_t * delay, sample_t bias);
void a52_imdct_512 (sample_t * data, sample_t * delay, sample_t bias);

View File

@ -0,0 +1,29 @@
/*
* attributes.h
* Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of a52dec, a free ATSC A-52 stream decoder.
* See http://liba52.sourceforge.net/ for updates.
*
* a52dec 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.
*
* a52dec is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* use gcc attribs to align critical data structures */
#ifdef ATTRIBUTE_ALIGNED_MAX
#define ATTR_ALIGN(align) __attribute__ ((__aligned__ ((ATTRIBUTE_ALIGNED_MAX < align) ? ATTRIBUTE_ALIGNED_MAX : align)))
#else
#define ATTR_ALIGN(align)
#endif

View File

@ -0,0 +1,265 @@
/*
* bit_allocate.c
* Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of a52dec, a free ATSC A-52 stream decoder.
* See http://liba52.sourceforge.net/ for updates.
*
* a52dec 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.
*
* a52dec is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "inttypes.h"
#include "a52.h"
#include "a52_internal.h"
static int hthtab[3][50] = {
{0x730, 0x730, 0x7c0, 0x800, 0x820, 0x840, 0x850, 0x850, 0x860, 0x860,
0x860, 0x860, 0x860, 0x870, 0x870, 0x870, 0x880, 0x880, 0x890, 0x890,
0x8a0, 0x8a0, 0x8b0, 0x8b0, 0x8c0, 0x8c0, 0x8d0, 0x8e0, 0x8f0, 0x900,
0x910, 0x910, 0x910, 0x910, 0x900, 0x8f0, 0x8c0, 0x870, 0x820, 0x7e0,
0x7a0, 0x770, 0x760, 0x7a0, 0x7c0, 0x7c0, 0x6e0, 0x400, 0x3c0, 0x3c0},
{0x710, 0x710, 0x7a0, 0x7f0, 0x820, 0x830, 0x840, 0x850, 0x850, 0x860,
0x860, 0x860, 0x860, 0x860, 0x870, 0x870, 0x870, 0x880, 0x880, 0x880,
0x890, 0x890, 0x8a0, 0x8a0, 0x8b0, 0x8b0, 0x8c0, 0x8c0, 0x8e0, 0x8f0,
0x900, 0x910, 0x910, 0x910, 0x910, 0x900, 0x8e0, 0x8b0, 0x870, 0x820,
0x7e0, 0x7b0, 0x760, 0x770, 0x7a0, 0x7c0, 0x780, 0x5d0, 0x3c0, 0x3c0},
{0x680, 0x680, 0x750, 0x7b0, 0x7e0, 0x810, 0x820, 0x830, 0x840, 0x850,
0x850, 0x850, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860, 0x860,
0x870, 0x870, 0x870, 0x870, 0x880, 0x880, 0x880, 0x890, 0x8a0, 0x8b0,
0x8c0, 0x8d0, 0x8e0, 0x8f0, 0x900, 0x910, 0x910, 0x910, 0x900, 0x8f0,
0x8d0, 0x8b0, 0x840, 0x7f0, 0x790, 0x760, 0x7a0, 0x7c0, 0x7b0, 0x720}
};
static int8_t baptab[305] = {
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, /* 93 padding elems */
16, 16, 16, 16, 16, 16, 16, 16, 16, 14, 14, 14, 14, 14, 14, 14,
14, 12, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 10, 9, 9, 9,
9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5,
5, 4, 4, -3, -3, 3, 3, 3, -2, -2, -1, -1, -1, -1, -1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0 /* 148 padding elems */
};
static int bndtab[30] = {21, 22, 23, 24, 25, 26, 27, 28, 31, 34,
37, 40, 43, 46, 49, 55, 61, 67, 73, 79,
85, 97, 109, 121, 133, 157, 181, 205, 229, 253};
static int8_t latab[256] = {
-64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53,
-52, -52, -51, -50, -49, -48, -47, -47, -46, -45, -44, -44,
-43, -42, -41, -41, -40, -39, -38, -38, -37, -36, -36, -35,
-35, -34, -33, -33, -32, -32, -31, -30, -30, -29, -29, -28,
-28, -27, -27, -26, -26, -25, -25, -24, -24, -23, -23, -22,
-22, -21, -21, -21, -20, -20, -19, -19, -19, -18, -18, -18,
-17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, -14,
-13, -13, -13, -13, -12, -12, -12, -12, -11, -11, -11, -11,
-10, -10, -10, -10, -10, -9, -9, -9, -9, -9, -8, -8,
-8, -8, -8, -8, -7, -7, -7, -7, -7, -7, -6, -6,
-6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5,
-5, -5, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
-4, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
-3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0
};
#define UPDATE_LEAK() \
do { \
fastleak += fdecay; \
if (fastleak > psd + fgain) \
fastleak = psd + fgain; \
slowleak += sdecay; \
if (slowleak > psd + sgain) \
slowleak = psd + sgain; \
} while (0)
#define COMPUTE_MASK() \
do { \
if (psd > dbknee) \
mask -= (psd - dbknee) >> 2; \
if (mask > hth [i >> halfrate]) \
mask = hth [i >> halfrate]; \
mask -= snroffset + 128 * deltba[i]; \
mask = (mask > 0) ? 0 : ((-mask) >> 5); \
mask -= floor; \
} while (0)
void a52_bit_allocate (a52_state_t * state, ba_t * ba, int bndstart,
int start, int end, int fastleak, int slowleak,
expbap_t * expbap)
{
static int slowgain[4] = {0x540, 0x4d8, 0x478, 0x410};
static int dbpbtab[4] = {0xc00, 0x500, 0x300, 0x100};
static int floortab[8] = {0x910, 0x950, 0x990, 0x9d0,
0xa10, 0xa90, 0xb10, 0x1400};
int i, j;
uint8_t * exp;
int8_t * bap;
int fdecay, fgain, sdecay, sgain, dbknee, floor, snroffset;
int psd, mask;
int8_t * deltba;
int * hth;
int halfrate;
halfrate = state->halfrate;
fdecay = (63 + 20 * ((state->bai >> 7) & 3)) >> halfrate; /* fdcycod */
fgain = 128 + 128 * (ba->bai & 7); /* fgaincod */
sdecay = (15 + 2 * (state->bai >> 9)) >> halfrate; /* sdcycod */
sgain = slowgain[(state->bai >> 5) & 3]; /* sgaincod */
dbknee = dbpbtab[(state->bai >> 3) & 3]; /* dbpbcod */
hth = hthtab[state->fscod];
/*
* if there is no delta bit allocation, make deltba point to an area
* known to contain zeroes. baptab+156 here.
*/
deltba = (ba->deltbae == DELTA_BIT_NONE) ? baptab + 156 : ba->deltba;
floor = floortab[state->bai & 7]; /* floorcod */
snroffset = 960 - 64 * state->csnroffst - 4 * (ba->bai >> 3) + floor;
floor >>= 5;
exp = expbap->exp;
bap = expbap->bap;
i = bndstart;
j = start;
if (start == 0) { /* not the coupling channel */
int lowcomp;
lowcomp = 0;
j = end - 1;
do {
if (i < j) {
if (exp[i+1] == exp[i] - 2)
lowcomp = 384;
else if (lowcomp && (exp[i+1] > exp[i]))
lowcomp -= 64;
}
psd = 128 * exp[i];
mask = psd + fgain + lowcomp;
COMPUTE_MASK ();
bap[i] = (baptab+156)[mask + 4 * exp[i]];
i++;
} while ((i < 3) || ((i < 7) && (exp[i] > exp[i-1])));
fastleak = psd + fgain;
slowleak = psd + sgain;
while (i < 7) {
if (i < j) {
if (exp[i+1] == exp[i] - 2)
lowcomp = 384;
else if (lowcomp && (exp[i+1] > exp[i]))
lowcomp -= 64;
}
psd = 128 * exp[i];
UPDATE_LEAK ();
mask = ((fastleak + lowcomp < slowleak) ?
fastleak + lowcomp : slowleak);
COMPUTE_MASK ();
bap[i] = (baptab+156)[mask + 4 * exp[i]];
i++;
}
if (end == 7) /* lfe channel */
return;
do {
if (exp[i+1] == exp[i] - 2)
lowcomp = 320;
else if (lowcomp && (exp[i+1] > exp[i]))
lowcomp -= 64;
psd = 128 * exp[i];
UPDATE_LEAK ();
mask = ((fastleak + lowcomp < slowleak) ?
fastleak + lowcomp : slowleak);
COMPUTE_MASK ();
bap[i] = (baptab+156)[mask + 4 * exp[i]];
i++;
} while (i < 20);
while (lowcomp > 128) { /* two iterations maximum */
lowcomp -= 128;
psd = 128 * exp[i];
UPDATE_LEAK ();
mask = ((fastleak + lowcomp < slowleak) ?
fastleak + lowcomp : slowleak);
COMPUTE_MASK ();
bap[i] = (baptab+156)[mask + 4 * exp[i]];
i++;
}
j = i;
}
do {
int startband, endband;
startband = j;
endband = ((bndtab-20)[i] < end) ? (bndtab-20)[i] : end;
psd = 128 * exp[j++];
while (j < endband) {
int next, delta;
next = 128 * exp[j++];
delta = next - psd;
switch (delta >> 9) {
case -6: case -5: case -4: case -3: case -2:
psd = next;
break;
case -1:
psd = next + latab[(-delta) >> 1];
break;
case 0:
psd += latab[delta >> 1];
break;
}
}
/* minpsd = -289 */
UPDATE_LEAK ();
mask = (fastleak < slowleak) ? fastleak : slowleak;
COMPUTE_MASK ();
i++;
j = startband;
do {
/* max(mask+4*exp)=147=-(minpsd+fgain-deltba-snroffset)>>5+4*exp */
/* min(mask+4*exp)=-156=-(sgain-deltba-snroffset)>>5 */
bap[j] = (baptab+156)[mask + 4 * exp[j]];
} while (++j < endband);
} while (j < end);
}

View File

@ -0,0 +1,95 @@
/*
* bitstream.c
* Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of a52dec, a free ATSC A-52 stream decoder.
* See http://liba52.sourceforge.net/ for updates.
*
* a52dec 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.
*
* a52dec is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "inttypes.h"
#include "a52.h"
#include "a52_internal.h"
#include "bitstream.h"
#define BUFFER_SIZE 4096
void a52_bitstream_set_ptr (a52_state_t * state, uint8_t * buf)
{
int align;
align = (long)buf & 3;
state->buffer_start = (uint32_t *) (buf - align);
state->bits_left = 0;
bitstream_get (state, align * 8);
}
static inline void bitstream_fill_current (a52_state_t * state)
{
uint32_t tmp;
tmp = *(state->buffer_start++);
state->current_word = swab32 (tmp);
}
/*
* The fast paths for _get is in the
* bitstream.h header file so it can be inlined.
*
* The "bottom half" of this routine is suffixed _bh
*
* -ah
*/
uint32_t a52_bitstream_get_bh (a52_state_t * state, uint32_t num_bits)
{
uint32_t result;
num_bits -= state->bits_left;
result = ((state->current_word << (32 - state->bits_left)) >>
(32 - state->bits_left));
bitstream_fill_current (state);
if (num_bits != 0)
result = (result << num_bits) | (state->current_word >> (32 - num_bits));
state->bits_left = 32 - num_bits;
return result;
}
int32_t a52_bitstream_get_bh_2 (a52_state_t * state, uint32_t num_bits)
{
int32_t result;
num_bits -= state->bits_left;
result = ((((int32_t)state->current_word) << (32 - state->bits_left)) >>
(32 - state->bits_left));
bitstream_fill_current(state);
if (num_bits != 0)
result = (result << num_bits) | (state->current_word >> (32 - num_bits));
state->bits_left = 32 - num_bits;
return result;
}

View File

@ -0,0 +1,77 @@
/*
* bitstream.h
* Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of a52dec, a free ATSC A-52 stream decoder.
* See http://liba52.sourceforge.net/ for updates.
*
* a52dec 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.
*
* a52dec is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* (stolen from the kernel) */
#ifdef WORDS_BIGENDIAN
# define swab32(x) (x)
#else
# if 0 && defined (__i386__)
# define swab32(x) __i386_swab32(x)
static inline const uint32_t __i386_swab32(uint32_t x)
{
__asm__("bswap %0" : "=r" (x) : "0" (x));
return x;
}
# else
# define swab32(x)\
((((uint8_t*)&x)[0] << 24) | (((uint8_t*)&x)[1] << 16) | \
(((uint8_t*)&x)[2] << 8) | (((uint8_t*)&x)[3]))
# endif
#endif
void a52_bitstream_set_ptr (a52_state_t * state, uint8_t * buf);
uint32_t a52_bitstream_get_bh (a52_state_t * state, uint32_t num_bits);
int32_t a52_bitstream_get_bh_2 (a52_state_t * state, uint32_t num_bits);
static inline uint32_t bitstream_get (a52_state_t * state, uint32_t num_bits)
{
uint32_t result;
if (num_bits < state->bits_left) {
result = (state->current_word << (32 - state->bits_left)) >> (32 - num_bits);
state->bits_left -= num_bits;
return result;
}
return a52_bitstream_get_bh (state, num_bits);
}
static inline int32_t bitstream_get_2 (a52_state_t * state, uint32_t num_bits)
{
int32_t result;
if (num_bits < state->bits_left) {
result = (((int32_t)state->current_word) << (32 - state->bits_left)) >> (32 - num_bits);
state->bits_left -= num_bits;
return result;
}
return a52_bitstream_get_bh_2 (state, num_bits);
}

View File

@ -0,0 +1,124 @@
/* vc++/config.h - manually adapted from include/config.h.in */
/* maximum supported data alignment */
/* #undef ATTRIBUTE_ALIGNED_MAX */
/* Define to 1 if you have the <dlfcn.h> header file. */
/* #undef HAVE_DLFCN_H */
/* Define to 1 if you have the `ftime' function. */
#define HAVE_FTIME 1
/* Define to 1 if you have the `gettimeofday' function. */
/* #undef HAVE_GETTIMEOFDAY */
/* Define to 1 if you have the <inttypes.h> header file. */
/* #undef HAVE_INTTYPES_H */
/* Define to 1 if you have the <io.h> header file. */
#define HAVE_IO_H 1
/* Define to 1 if you have the `memalign' function. */
/* #undef HAVE_MEMALIGN */
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the <stdint.h> header file. */
/* #undef HAVE_STDINT_H */
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
/* #undef HAVE_STRINGS_H */
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/timeb.h> header file. */
#define HAVE_SYS_TIMEB_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
/* #undef HAVE_SYS_TIME_H */
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
/* #undef HAVE_UNISTD_H */
/* liba52 djbfft support */
/* #undef LIBA52_DJBFFT */
/* a52 sample precision */
/* #undef LIBA52_DOUBLE */
/* libao al support */
/* #undef LIBAO_AL */
/* libao OSS support */
/* #undef LIBAO_OSS */
/* libao solaris support */
/* #undef LIBAO_SOLARIS */
/* libao win support */
#define LIBAO_WIN
/* Name of package */
#define PACKAGE "a52dec"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME ""
/* Define to the full name and version of this package. */
#define PACKAGE_STRING ""
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME ""
/* Define to the version of this package. */
#define PACKAGE_VERSION ""
/* Define as the return type of signal handlers (`int' or `void'). */
#define RETSIGTYPE void
/* The size of a `char', as computed by sizeof. */
#define SIZEOF_CHAR 1
/* The size of a `int', as computed by sizeof. */
#define SIZEOF_INT 4
/* The size of a `short', as computed by sizeof. */
#define SIZEOF_SHORT 2
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "0.7.4-cvs"
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
/* #undef WORDS_BIGENDIAN */
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define as `__inline' if that's what the C compiler calls it, or to nothing
if it is not supported. */
#define inline __inline
/* Define as `__restrict' if that's what the C compiler calls it, or to
nothing if it is not supported. */
#define restrict /*__restrict*/
/* Define to `unsigned' if <sys/types.h> does not define. */
/* #undef size_t */

View File

@ -0,0 +1,19 @@
AC_SUBST([LIBA52_CFLAGS])
AC_SUBST([LIBA52_LIBS])
dnl avoid -fPIC when possible
LIBA52_CFLAGS="$LIBA52_CFLAGS -prefer-non-pic"
AC_ARG_ENABLE([double],
[ --enable-double use double-precision samples])
if test x"$enable_double" = x"yes"; then
AC_DEFINE([LIBA52_DOUBLE],,[a52 sample precision])
fi
dnl check for djbttf
AC_ARG_ENABLE([djbfft],
[ --enable-djbfft make a version using djbfft])
if test x"$enable_djbfft" = x"yes"; then
AC_DEFINE([LIBA52_DJBFFT],,[liba52 djbfft support])
LIBA52_LIBS="$LIBA52_LIBS -ldjbfft"
fi

View File

@ -0,0 +1,655 @@
/*
* downmix.c
* Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of a52dec, a free ATSC A-52 stream decoder.
* See http://liba52.sourceforge.net/ for updates.
*
* a52dec 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.
*
* a52dec is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma warning(disable:4244)
#include "config.h"
#include <string.h>
#include "inttypes.h"
#include "a52.h"
#include "a52_internal.h"
#define CONVERT(acmod,output) (((output) << 3) + (acmod))
int a52_downmix_init (int input, int flags, sample_t * level,
sample_t clev, sample_t slev)
{
static uint8_t table[11][8] = {
{A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO,
A52_STEREO, A52_STEREO, A52_STEREO, A52_STEREO},
{A52_MONO, A52_MONO, A52_MONO, A52_MONO,
A52_MONO, A52_MONO, A52_MONO, A52_MONO},
{A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO,
A52_STEREO, A52_STEREO, A52_STEREO, A52_STEREO},
{A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_3F,
A52_STEREO, A52_3F, A52_STEREO, A52_3F},
{A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO,
A52_2F1R, A52_2F1R, A52_2F1R, A52_2F1R},
{A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_STEREO,
A52_2F1R, A52_3F1R, A52_2F1R, A52_3F1R},
{A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_3F,
A52_2F2R, A52_2F2R, A52_2F2R, A52_2F2R},
{A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_3F,
A52_2F2R, A52_3F2R, A52_2F2R, A52_3F2R},
{A52_CHANNEL1, A52_MONO, A52_MONO, A52_MONO,
A52_MONO, A52_MONO, A52_MONO, A52_MONO},
{A52_CHANNEL2, A52_MONO, A52_MONO, A52_MONO,
A52_MONO, A52_MONO, A52_MONO, A52_MONO},
{A52_CHANNEL, A52_DOLBY, A52_STEREO, A52_DOLBY,
A52_DOLBY, A52_DOLBY, A52_DOLBY, A52_DOLBY}
};
int output;
output = flags & A52_CHANNEL_MASK;
if (output > A52_DOLBY)
return -1;
output = table[output][input & 7];
if ((output == A52_STEREO) &&
((input == A52_DOLBY) || ((input == A52_3F) && (clev == LEVEL_3DB))))
output = A52_DOLBY;
if (flags & A52_ADJUST_LEVEL)
switch (CONVERT (input & 7, output)) {
case CONVERT (A52_3F, A52_MONO):
*level *= LEVEL_3DB / (1 + clev);
break;
case CONVERT (A52_STEREO, A52_MONO):
case CONVERT (A52_2F2R, A52_2F1R):
case CONVERT (A52_3F2R, A52_3F1R):
level_3db:
*level *= LEVEL_3DB;
break;
case CONVERT (A52_3F2R, A52_2F1R):
if (clev < LEVEL_PLUS3DB - 1)
goto level_3db;
/* break thru */
case CONVERT (A52_3F, A52_STEREO):
case CONVERT (A52_3F1R, A52_2F1R):
case CONVERT (A52_3F1R, A52_2F2R):
case CONVERT (A52_3F2R, A52_2F2R):
*level /= 1 + clev;
break;
case CONVERT (A52_2F1R, A52_MONO):
*level *= LEVEL_PLUS3DB / (2 + slev);
break;
case CONVERT (A52_2F1R, A52_STEREO):
case CONVERT (A52_3F1R, A52_3F):
*level /= 1 + slev * LEVEL_3DB;
break;
case CONVERT (A52_3F1R, A52_MONO):
*level *= LEVEL_3DB / (1 + clev + 0.5 * slev);
break;
case CONVERT (A52_3F1R, A52_STEREO):
*level /= 1 + clev + slev * LEVEL_3DB;
break;
case CONVERT (A52_2F2R, A52_MONO):
*level *= LEVEL_3DB / (1 + slev);
break;
case CONVERT (A52_2F2R, A52_STEREO):
case CONVERT (A52_3F2R, A52_3F):
*level /= 1 + slev;
break;
case CONVERT (A52_3F2R, A52_MONO):
*level *= LEVEL_3DB / (1 + clev + slev);
break;
case CONVERT (A52_3F2R, A52_STEREO):
*level /= 1 + clev + slev;
break;
case CONVERT (A52_MONO, A52_DOLBY):
*level *= LEVEL_PLUS3DB;
break;
case CONVERT (A52_3F, A52_DOLBY):
case CONVERT (A52_2F1R, A52_DOLBY):
*level *= 1 / (1 + LEVEL_3DB);
break;
case CONVERT (A52_3F1R, A52_DOLBY):
case CONVERT (A52_2F2R, A52_DOLBY):
*level *= 1 / (1 + 2 * LEVEL_3DB);
break;
case CONVERT (A52_3F2R, A52_DOLBY):
*level *= 1 / (1 + 3 * LEVEL_3DB);
break;
}
return output;
}
int a52_downmix_coeff (sample_t * coeff, int acmod, int output, sample_t level,
sample_t clev, sample_t slev)
{
switch (CONVERT (acmod, output & A52_CHANNEL_MASK)) {
case CONVERT (A52_CHANNEL, A52_CHANNEL):
case CONVERT (A52_MONO, A52_MONO):
case CONVERT (A52_STEREO, A52_STEREO):
case CONVERT (A52_3F, A52_3F):
case CONVERT (A52_2F1R, A52_2F1R):
case CONVERT (A52_3F1R, A52_3F1R):
case CONVERT (A52_2F2R, A52_2F2R):
case CONVERT (A52_3F2R, A52_3F2R):
case CONVERT (A52_STEREO, A52_DOLBY):
coeff[0] = coeff[1] = coeff[2] = coeff[3] = coeff[4] = level;
return 0;
case CONVERT (A52_CHANNEL, A52_MONO):
coeff[0] = coeff[1] = level * LEVEL_6DB;
return 3;
case CONVERT (A52_STEREO, A52_MONO):
coeff[0] = coeff[1] = level * LEVEL_3DB;
return 3;
case CONVERT (A52_3F, A52_MONO):
coeff[0] = coeff[2] = level * LEVEL_3DB;
coeff[1] = level * clev * LEVEL_PLUS3DB;
return 7;
case CONVERT (A52_2F1R, A52_MONO):
coeff[0] = coeff[1] = level * LEVEL_3DB;
coeff[2] = level * slev * LEVEL_3DB;
return 7;
case CONVERT (A52_2F2R, A52_MONO):
coeff[0] = coeff[1] = level * LEVEL_3DB;
coeff[2] = coeff[3] = level * slev * LEVEL_3DB;
return 15;
case CONVERT (A52_3F1R, A52_MONO):
coeff[0] = coeff[2] = level * LEVEL_3DB;
coeff[1] = level * clev * LEVEL_PLUS3DB;
coeff[3] = level * slev * LEVEL_3DB;
return 15;
case CONVERT (A52_3F2R, A52_MONO):
coeff[0] = coeff[2] = level * LEVEL_3DB;
coeff[1] = level * clev * LEVEL_PLUS3DB;
coeff[3] = coeff[4] = level * slev * LEVEL_3DB;
return 31;
case CONVERT (A52_MONO, A52_DOLBY):
coeff[0] = level * LEVEL_3DB;
return 0;
case CONVERT (A52_3F, A52_DOLBY):
clev = LEVEL_3DB;
case CONVERT (A52_3F, A52_STEREO):
case CONVERT (A52_3F1R, A52_2F1R):
case CONVERT (A52_3F2R, A52_2F2R):
coeff[0] = coeff[2] = coeff[3] = coeff[4] = level;
coeff[1] = level * clev;
return 7;
case CONVERT (A52_2F1R, A52_DOLBY):
slev = 1;
case CONVERT (A52_2F1R, A52_STEREO):
coeff[0] = coeff[1] = level;
coeff[2] = level * slev * LEVEL_3DB;
return 7;
case CONVERT (A52_3F1R, A52_DOLBY):
clev = LEVEL_3DB;
slev = 1;
case CONVERT (A52_3F1R, A52_STEREO):
coeff[0] = coeff[2] = level;
coeff[1] = level * clev;
coeff[3] = level * slev * LEVEL_3DB;
return 15;
case CONVERT (A52_2F2R, A52_DOLBY):
slev = LEVEL_3DB;
case CONVERT (A52_2F2R, A52_STEREO):
coeff[0] = coeff[1] = level;
coeff[2] = coeff[3] = level * slev;
return 15;
case CONVERT (A52_3F2R, A52_DOLBY):
clev = LEVEL_3DB;
case CONVERT (A52_3F2R, A52_2F1R):
slev = LEVEL_3DB;
case CONVERT (A52_3F2R, A52_STEREO):
coeff[0] = coeff[2] = level;
coeff[1] = level * clev;
coeff[3] = coeff[4] = level * slev;
return 31;
case CONVERT (A52_3F1R, A52_3F):
coeff[0] = coeff[1] = coeff[2] = level;
coeff[3] = level * slev * LEVEL_3DB;
return 13;
case CONVERT (A52_3F2R, A52_3F):
coeff[0] = coeff[1] = coeff[2] = level;
coeff[3] = coeff[4] = level * slev;
return 29;
case CONVERT (A52_2F2R, A52_2F1R):
coeff[0] = coeff[1] = level;
coeff[2] = coeff[3] = level * LEVEL_3DB;
return 12;
case CONVERT (A52_3F2R, A52_3F1R):
coeff[0] = coeff[1] = coeff[2] = level;
coeff[3] = coeff[4] = level * LEVEL_3DB;
return 24;
case CONVERT (A52_2F1R, A52_2F2R):
coeff[0] = coeff[1] = level;
coeff[2] = level * LEVEL_3DB;
return 0;
case CONVERT (A52_3F1R, A52_2F2R):
coeff[0] = coeff[2] = level;
coeff[1] = level * clev;
coeff[3] = level * LEVEL_3DB;
return 7;
case CONVERT (A52_3F1R, A52_3F2R):
coeff[0] = coeff[1] = coeff[2] = level;
coeff[3] = level * LEVEL_3DB;
return 0;
case CONVERT (A52_CHANNEL, A52_CHANNEL1):
coeff[0] = level;
coeff[1] = 0;
return 0;
case CONVERT (A52_CHANNEL, A52_CHANNEL2):
coeff[0] = 0;
coeff[1] = level;
return 0;
}
return -1; /* NOTREACHED */
}
static void mix2to1 (sample_t * dest, sample_t * src, sample_t bias)
{
int i;
for (i = 0; i < 256; i++)
dest[i] += src[i] + bias;
}
static void mix3to1 (sample_t * samples, sample_t bias)
{
int i;
for (i = 0; i < 256; i++)
samples[i] += samples[i + 256] + samples[i + 512] + bias;
}
static void mix4to1 (sample_t * samples, sample_t bias)
{
int i;
for (i = 0; i < 256; i++)
samples[i] += (samples[i + 256] + samples[i + 512] +
samples[i + 768] + bias);
}
static void mix5to1 (sample_t * samples, sample_t bias)
{
int i;
for (i = 0; i < 256; i++)
samples[i] += (samples[i + 256] + samples[i + 512] +
samples[i + 768] + samples[i + 1024] + bias);
}
static void mix3to2 (sample_t * samples, sample_t bias)
{
int i;
sample_t common;
for (i = 0; i < 256; i++) {
common = samples[i + 256] + bias;
samples[i] += common;
samples[i + 256] = samples[i + 512] + common;
}
}
static void mix21to2 (sample_t * left, sample_t * right, sample_t bias)
{
int i;
sample_t common;
for (i = 0; i < 256; i++) {
common = right[i + 256] + bias;
left[i] += common;
right[i] += common;
}
}
static void mix21toS (sample_t * samples, sample_t bias)
{
int i;
sample_t surround;
for (i = 0; i < 256; i++) {
surround = samples[i + 512];
samples[i] += bias - surround;
samples[i + 256] += bias + surround;
}
}
static void mix31to2 (sample_t * samples, sample_t bias)
{
int i;
sample_t common;
for (i = 0; i < 256; i++) {
common = samples[i + 256] + samples[i + 768] + bias;
samples[i] += common;
samples[i + 256] = samples[i + 512] + common;
}
}
static void mix31toS (sample_t * samples, sample_t bias)
{
int i;
sample_t common, surround;
for (i = 0; i < 256; i++) {
common = samples[i + 256] + bias;
surround = samples[i + 768];
samples[i] += common - surround;
samples[i + 256] = samples[i + 512] + common + surround;
}
}
static void mix22toS (sample_t * samples, sample_t bias)
{
int i;
sample_t surround;
for (i = 0; i < 256; i++) {
surround = samples[i + 512] + samples[i + 768];
samples[i] += bias - surround;
samples[i + 256] += bias + surround;
}
}
static void mix32to2 (sample_t * samples, sample_t bias)
{
int i;
sample_t common;
for (i = 0; i < 256; i++) {
common = samples[i + 256] + bias;
samples[i] += common + samples[i + 768];
samples[i + 256] = common + samples[i + 512] + samples[i + 1024];
}
}
static void mix32toS (sample_t * samples, sample_t bias)
{
int i;
sample_t common, surround;
for (i = 0; i < 256; i++) {
common = samples[i + 256] + bias;
surround = samples[i + 768] + samples[i + 1024];
samples[i] += common - surround;
samples[i + 256] = samples[i + 512] + common + surround;
}
}
static void move2to1 (sample_t * src, sample_t * dest, sample_t bias)
{
int i;
for (i = 0; i < 256; i++)
dest[i] = src[i] + src[i + 256] + bias;
}
static void zero (sample_t * samples)
{
int i;
for (i = 0; i < 256; i++)
samples[i] = 0;
}
void a52_downmix (sample_t * samples, int acmod, int output, sample_t bias,
sample_t clev, sample_t slev)
{
switch (CONVERT (acmod, output & A52_CHANNEL_MASK)) {
case CONVERT (A52_CHANNEL, A52_CHANNEL2):
memcpy (samples, samples + 256, 256 * sizeof (sample_t));
break;
case CONVERT (A52_CHANNEL, A52_MONO):
case CONVERT (A52_STEREO, A52_MONO):
mix_2to1:
mix2to1 (samples, samples + 256, bias);
break;
case CONVERT (A52_2F1R, A52_MONO):
if (slev == 0)
goto mix_2to1;
case CONVERT (A52_3F, A52_MONO):
mix_3to1:
mix3to1 (samples, bias);
break;
case CONVERT (A52_3F1R, A52_MONO):
if (slev == 0)
goto mix_3to1;
case CONVERT (A52_2F2R, A52_MONO):
if (slev == 0)
goto mix_2to1;
mix4to1 (samples, bias);
break;
case CONVERT (A52_3F2R, A52_MONO):
if (slev == 0)
goto mix_3to1;
mix5to1 (samples, bias);
break;
case CONVERT (A52_MONO, A52_DOLBY):
memcpy (samples + 256, samples, 256 * sizeof (sample_t));
break;
case CONVERT (A52_3F, A52_STEREO):
case CONVERT (A52_3F, A52_DOLBY):
mix_3to2:
mix3to2 (samples, bias);
break;
case CONVERT (A52_2F1R, A52_STEREO):
if (slev == 0)
break;
mix21to2 (samples, samples + 256, bias);
break;
case CONVERT (A52_2F1R, A52_DOLBY):
mix21toS (samples, bias);
break;
case CONVERT (A52_3F1R, A52_STEREO):
if (slev == 0)
goto mix_3to2;
mix31to2 (samples, bias);
break;
case CONVERT (A52_3F1R, A52_DOLBY):
mix31toS (samples, bias);
break;
case CONVERT (A52_2F2R, A52_STEREO):
if (slev == 0)
break;
mix2to1 (samples, samples + 512, bias);
mix2to1 (samples + 256, samples + 768, bias);
break;
case CONVERT (A52_2F2R, A52_DOLBY):
mix22toS (samples, bias);
break;
case CONVERT (A52_3F2R, A52_STEREO):
if (slev == 0)
goto mix_3to2;
mix32to2 (samples, bias);
break;
case CONVERT (A52_3F2R, A52_DOLBY):
mix32toS (samples, bias);
break;
case CONVERT (A52_3F1R, A52_3F):
if (slev == 0)
break;
mix21to2 (samples, samples + 512, bias);
break;
case CONVERT (A52_3F2R, A52_3F):
if (slev == 0)
break;
mix2to1 (samples, samples + 768, bias);
mix2to1 (samples + 512, samples + 1024, bias);
break;
case CONVERT (A52_3F1R, A52_2F1R):
mix3to2 (samples, bias);
memcpy (samples + 512, samples + 768, 256 * sizeof (sample_t));
break;
case CONVERT (A52_2F2R, A52_2F1R):
mix2to1 (samples + 512, samples + 768, bias);
break;
case CONVERT (A52_3F2R, A52_2F1R):
mix3to2 (samples, bias);
move2to1 (samples + 768, samples + 512, bias);
break;
case CONVERT (A52_3F2R, A52_3F1R):
mix2to1 (samples + 768, samples + 1024, bias);
break;
case CONVERT (A52_2F1R, A52_2F2R):
memcpy (samples + 768, samples + 512, 256 * sizeof (sample_t));
break;
case CONVERT (A52_3F1R, A52_2F2R):
mix3to2 (samples, bias);
memcpy (samples + 512, samples + 768, 256 * sizeof (sample_t));
break;
case CONVERT (A52_3F2R, A52_2F2R):
mix3to2 (samples, bias);
memcpy (samples + 512, samples + 768, 256 * sizeof (sample_t));
memcpy (samples + 768, samples + 1024, 256 * sizeof (sample_t));
break;
case CONVERT (A52_3F1R, A52_3F2R):
memcpy (samples + 1027, samples + 768, 256 * sizeof (sample_t));
break;
}
}
void a52_upmix (sample_t * samples, int acmod, int output)
{
switch (CONVERT (acmod, output & A52_CHANNEL_MASK)) {
case CONVERT (A52_CHANNEL, A52_CHANNEL2):
memcpy (samples + 256, samples, 256 * sizeof (sample_t));
break;
case CONVERT (A52_3F2R, A52_MONO):
zero (samples + 1024);
case CONVERT (A52_3F1R, A52_MONO):
case CONVERT (A52_2F2R, A52_MONO):
zero (samples + 768);
case CONVERT (A52_3F, A52_MONO):
case CONVERT (A52_2F1R, A52_MONO):
zero (samples + 512);
case CONVERT (A52_CHANNEL, A52_MONO):
case CONVERT (A52_STEREO, A52_MONO):
zero (samples + 256);
break;
case CONVERT (A52_3F2R, A52_STEREO):
case CONVERT (A52_3F2R, A52_DOLBY):
zero (samples + 1024);
case CONVERT (A52_3F1R, A52_STEREO):
case CONVERT (A52_3F1R, A52_DOLBY):
zero (samples + 768);
case CONVERT (A52_3F, A52_STEREO):
case CONVERT (A52_3F, A52_DOLBY):
mix_3to2:
memcpy (samples + 512, samples + 256, 256 * sizeof (sample_t));
zero (samples + 256);
break;
case CONVERT (A52_2F2R, A52_STEREO):
case CONVERT (A52_2F2R, A52_DOLBY):
zero (samples + 768);
case CONVERT (A52_2F1R, A52_STEREO):
case CONVERT (A52_2F1R, A52_DOLBY):
zero (samples + 512);
break;
case CONVERT (A52_3F2R, A52_3F):
zero (samples + 1024);
case CONVERT (A52_3F1R, A52_3F):
case CONVERT (A52_2F2R, A52_2F1R):
zero (samples + 768);
break;
case CONVERT (A52_3F2R, A52_3F1R):
zero (samples + 1024);
break;
case CONVERT (A52_3F2R, A52_2F1R):
zero (samples + 1024);
case CONVERT (A52_3F1R, A52_2F1R):
mix_31to21:
memcpy (samples + 768, samples + 512, 256 * sizeof (sample_t));
goto mix_3to2;
case CONVERT (A52_3F2R, A52_2F2R):
memcpy (samples + 1024, samples + 768, 256 * sizeof (sample_t));
goto mix_31to21;
}
}

View File

@ -0,0 +1,432 @@
/*
* imdct.c
* Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* The ifft algorithms in this file have been largely inspired by Dan
* Bernstein's work, djbfft, available at http://cr.yp.to/djbfft.html
*
* This file is part of a52dec, a free ATSC A-52 stream decoder.
* See http://liba52.sourceforge.net/ for updates.
*
* a52dec 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.
*
* a52dec is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma warning(disable:4244)
#include "config.h"
#include <math.h>
#include <stdio.h>
#ifdef LIBA52_DJBFFT
#include <fftc4.h>
#endif
#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795029
#endif
#include "inttypes.h"
#include "a52.h"
#include "a52_internal.h"
#include "mm_accel.h"
typedef struct complex_s {
sample_t real;
sample_t imag;
} complex_t;
static uint8_t fftorder[] = {
0,128, 64,192, 32,160,224, 96, 16,144, 80,208,240,112, 48,176,
8,136, 72,200, 40,168,232,104,248,120, 56,184, 24,152,216, 88,
4,132, 68,196, 36,164,228,100, 20,148, 84,212,244,116, 52,180,
252,124, 60,188, 28,156,220, 92, 12,140, 76,204,236,108, 44,172,
2,130, 66,194, 34,162,226, 98, 18,146, 82,210,242,114, 50,178,
10,138, 74,202, 42,170,234,106,250,122, 58,186, 26,154,218, 90,
254,126, 62,190, 30,158,222, 94, 14,142, 78,206,238,110, 46,174,
6,134, 70,198, 38,166,230,102,246,118, 54,182, 22,150,214, 86
};
/* Root values for IFFT */
static sample_t roots16[3];
static sample_t roots32[7];
static sample_t roots64[15];
static sample_t roots128[31];
/* Twiddle factors for IMDCT */
static complex_t pre1[128];
static complex_t post1[64];
static complex_t pre2[64];
static complex_t post2[32];
static sample_t a52_imdct_window[256];
static void (* ifft128) (complex_t * buf);
static void (* ifft64) (complex_t * buf);
static inline void ifft2 (complex_t * buf)
{
double r, i;
r = buf[0].real;
i = buf[0].imag;
buf[0].real += buf[1].real;
buf[0].imag += buf[1].imag;
buf[1].real = r - buf[1].real;
buf[1].imag = i - buf[1].imag;
}
static inline void ifft4 (complex_t * buf)
{
double tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8;
tmp1 = buf[0].real + buf[1].real;
tmp2 = buf[3].real + buf[2].real;
tmp3 = buf[0].imag + buf[1].imag;
tmp4 = buf[2].imag + buf[3].imag;
tmp5 = buf[0].real - buf[1].real;
tmp6 = buf[0].imag - buf[1].imag;
tmp7 = buf[2].imag - buf[3].imag;
tmp8 = buf[3].real - buf[2].real;
buf[0].real = tmp1 + tmp2;
buf[0].imag = tmp3 + tmp4;
buf[2].real = tmp1 - tmp2;
buf[2].imag = tmp3 - tmp4;
buf[1].real = tmp5 + tmp7;
buf[1].imag = tmp6 + tmp8;
buf[3].real = tmp5 - tmp7;
buf[3].imag = tmp6 - tmp8;
}
/* the basic split-radix ifft butterfly */
#define BUTTERFLY(a0,a1,a2,a3,wr,wi) do { \
tmp5 = a2.real * wr + a2.imag * wi; \
tmp6 = a2.imag * wr - a2.real * wi; \
tmp7 = a3.real * wr - a3.imag * wi; \
tmp8 = a3.imag * wr + a3.real * wi; \
tmp1 = tmp5 + tmp7; \
tmp2 = tmp6 + tmp8; \
tmp3 = tmp6 - tmp8; \
tmp4 = tmp7 - tmp5; \
a2.real = a0.real - tmp1; \
a2.imag = a0.imag - tmp2; \
a3.real = a1.real - tmp3; \
a3.imag = a1.imag - tmp4; \
a0.real += tmp1; \
a0.imag += tmp2; \
a1.real += tmp3; \
a1.imag += tmp4; \
} while (0)
/* split-radix ifft butterfly, specialized for wr=1 wi=0 */
#define BUTTERFLY_ZERO(a0,a1,a2,a3) do { \
tmp1 = a2.real + a3.real; \
tmp2 = a2.imag + a3.imag; \
tmp3 = a2.imag - a3.imag; \
tmp4 = a3.real - a2.real; \
a2.real = a0.real - tmp1; \
a2.imag = a0.imag - tmp2; \
a3.real = a1.real - tmp3; \
a3.imag = a1.imag - tmp4; \
a0.real += tmp1; \
a0.imag += tmp2; \
a1.real += tmp3; \
a1.imag += tmp4; \
} while (0)
/* split-radix ifft butterfly, specialized for wr=wi */
#define BUTTERFLY_HALF(a0,a1,a2,a3,w) do { \
tmp5 = (a2.real + a2.imag) * w; \
tmp6 = (a2.imag - a2.real) * w; \
tmp7 = (a3.real - a3.imag) * w; \
tmp8 = (a3.imag + a3.real) * w; \
tmp1 = tmp5 + tmp7; \
tmp2 = tmp6 + tmp8; \
tmp3 = tmp6 - tmp8; \
tmp4 = tmp7 - tmp5; \
a2.real = a0.real - tmp1; \
a2.imag = a0.imag - tmp2; \
a3.real = a1.real - tmp3; \
a3.imag = a1.imag - tmp4; \
a0.real += tmp1; \
a0.imag += tmp2; \
a1.real += tmp3; \
a1.imag += tmp4; \
} while (0)
static inline void ifft8 (complex_t * buf)
{
double tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8;
ifft4 (buf);
ifft2 (buf + 4);
ifft2 (buf + 6);
BUTTERFLY_ZERO (buf[0], buf[2], buf[4], buf[6]);
BUTTERFLY_HALF (buf[1], buf[3], buf[5], buf[7], roots16[1]);
}
static void ifft_pass (complex_t * buf, sample_t * weight, int n)
{
complex_t * buf1;
complex_t * buf2;
complex_t * buf3;
double tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8;
int i;
buf++;
buf1 = buf + n;
buf2 = buf + 2 * n;
buf3 = buf + 3 * n;
BUTTERFLY_ZERO (buf[-1], buf1[-1], buf2[-1], buf3[-1]);
i = n - 1;
do {
BUTTERFLY (buf[0], buf1[0], buf2[0], buf3[0], weight[n], weight[2*i]);
buf++;
buf1++;
buf2++;
buf3++;
weight++;
} while (--i);
}
static void ifft16 (complex_t * buf)
{
ifft8 (buf);
ifft4 (buf + 8);
ifft4 (buf + 12);
ifft_pass (buf, roots16 - 4, 4);
}
static void ifft32 (complex_t * buf)
{
ifft16 (buf);
ifft8 (buf + 16);
ifft8 (buf + 24);
ifft_pass (buf, roots32 - 8, 8);
}
static void ifft64_c (complex_t * buf)
{
ifft32 (buf);
ifft16 (buf + 32);
ifft16 (buf + 48);
ifft_pass (buf, roots64 - 16, 16);
}
static void ifft128_c (complex_t * buf)
{
ifft32 (buf);
ifft16 (buf + 32);
ifft16 (buf + 48);
ifft_pass (buf, roots64 - 16, 16);
ifft32 (buf + 64);
ifft32 (buf + 96);
ifft_pass (buf, roots128 - 32, 32);
}
void a52_imdct_512 (sample_t * data, sample_t * delay, sample_t bias)
{
int i, k;
sample_t t_r, t_i, a_r, a_i, b_r, b_i, w_1, w_2;
const sample_t * window = a52_imdct_window;
complex_t buf[128];
for (i = 0; i < 128; i++) {
k = fftorder[i];
t_r = pre1[i].real;
t_i = pre1[i].imag;
buf[i].real = t_i * data[255-k] + t_r * data[k];
buf[i].imag = t_r * data[255-k] - t_i * data[k];
}
ifft128 (buf);
/* Post IFFT complex multiply plus IFFT complex conjugate*/
/* Window and convert to real valued signal */
for (i = 0; i < 64; i++) {
/* y[n] = z[n] * (xcos1[n] + j * xsin1[n]) ; */
t_r = post1[i].real;
t_i = post1[i].imag;
a_r = t_r * buf[i].real + t_i * buf[i].imag;
a_i = t_i * buf[i].real - t_r * buf[i].imag;
b_r = t_i * buf[127-i].real + t_r * buf[127-i].imag;
b_i = t_r * buf[127-i].real - t_i * buf[127-i].imag;
w_1 = window[2*i];
w_2 = window[255-2*i];
data[2*i] = delay[2*i] * w_2 - a_r * w_1 + bias;
data[255-2*i] = delay[2*i] * w_1 + a_r * w_2 + bias;
delay[2*i] = a_i;
w_1 = window[2*i+1];
w_2 = window[254-2*i];
data[2*i+1] = delay[2*i+1] * w_2 + b_r * w_1 + bias;
data[254-2*i] = delay[2*i+1] * w_1 - b_r * w_2 + bias;
delay[2*i+1] = b_i;
}
}
void a52_imdct_256(sample_t * data, sample_t * delay, sample_t bias)
{
int i, k;
sample_t t_r, t_i, a_r, a_i, b_r, b_i, c_r, c_i, d_r, d_i, w_1, w_2;
const sample_t * window = a52_imdct_window;
complex_t buf1[64], buf2[64];
/* Pre IFFT complex multiply plus IFFT cmplx conjugate */
for (i = 0; i < 64; i++) {
k = fftorder[i];
t_r = pre2[i].real;
t_i = pre2[i].imag;
buf1[i].real = t_i * data[254-k] + t_r * data[k];
buf1[i].imag = t_r * data[254-k] - t_i * data[k];
buf2[i].real = t_i * data[255-k] + t_r * data[k+1];
buf2[i].imag = t_r * data[255-k] - t_i * data[k+1];
}
ifft64 (buf1);
ifft64 (buf2);
/* Post IFFT complex multiply */
/* Window and convert to real valued signal */
for (i = 0; i < 32; i++) {
/* y1[n] = z1[n] * (xcos2[n] + j * xs in2[n]) ; */
t_r = post2[i].real;
t_i = post2[i].imag;
a_r = t_r * buf1[i].real + t_i * buf1[i].imag;
a_i = t_i * buf1[i].real - t_r * buf1[i].imag;
b_r = t_i * buf1[63-i].real + t_r * buf1[63-i].imag;
b_i = t_r * buf1[63-i].real - t_i * buf1[63-i].imag;
c_r = t_r * buf2[i].real + t_i * buf2[i].imag;
c_i = t_i * buf2[i].real - t_r * buf2[i].imag;
d_r = t_i * buf2[63-i].real + t_r * buf2[63-i].imag;
d_i = t_r * buf2[63-i].real - t_i * buf2[63-i].imag;
w_1 = window[2*i];
w_2 = window[255-2*i];
data[2*i] = delay[2*i] * w_2 - a_r * w_1 + bias;
data[255-2*i] = delay[2*i] * w_1 + a_r * w_2 + bias;
delay[2*i] = c_i;
w_1 = window[128+2*i];
w_2 = window[127-2*i];
data[128+2*i] = delay[127-2*i] * w_2 + a_i * w_1 + bias;
data[127-2*i] = delay[127-2*i] * w_1 - a_i * w_2 + bias;
delay[127-2*i] = c_r;
w_1 = window[2*i+1];
w_2 = window[254-2*i];
data[2*i+1] = delay[2*i+1] * w_2 - b_i * w_1 + bias;
data[254-2*i] = delay[2*i+1] * w_1 + b_i * w_2 + bias;
delay[2*i+1] = d_r;
w_1 = window[129+2*i];
w_2 = window[126-2*i];
data[129+2*i] = delay[126-2*i] * w_2 + b_r * w_1 + bias;
data[126-2*i] = delay[126-2*i] * w_1 - b_r * w_2 + bias;
delay[126-2*i] = d_i;
}
}
static double besselI0 (double x)
{
double bessel = 1;
int i = 100;
do
bessel = bessel * x / (i * i) + 1;
while (--i);
return bessel;
}
void a52_imdct_init (uint32_t mm_accel)
{
int i, k;
double sum;
/* compute imdct window - kaiser-bessel derived window, alpha = 5.0 */
sum = 0;
for (i = 0; i < 256; i++) {
sum += besselI0 (i * (256 - i) * (5 * M_PI / 256) * (5 * M_PI / 256));
a52_imdct_window[i] = sum;
}
sum++;
for (i = 0; i < 256; i++)
a52_imdct_window[i] = sqrt (a52_imdct_window[i] / sum);
for (i = 0; i < 3; i++)
roots16[i] = cos ((M_PI / 8) * (i + 1));
for (i = 0; i < 7; i++)
roots32[i] = cos ((M_PI / 16) * (i + 1));
for (i = 0; i < 15; i++)
roots64[i] = cos ((M_PI / 32) * (i + 1));
for (i = 0; i < 31; i++)
roots128[i] = cos ((M_PI / 64) * (i + 1));
for (i = 0; i < 64; i++) {
k = fftorder[i] / 2 + 64;
pre1[i].real = cos ((M_PI / 256) * (k - 0.25));
pre1[i].imag = sin ((M_PI / 256) * (k - 0.25));
}
for (i = 64; i < 128; i++) {
k = fftorder[i] / 2 + 64;
pre1[i].real = -cos ((M_PI / 256) * (k - 0.25));
pre1[i].imag = -sin ((M_PI / 256) * (k - 0.25));
}
for (i = 0; i < 64; i++) {
post1[i].real = cos ((M_PI / 256) * (i + 0.5));
post1[i].imag = sin ((M_PI / 256) * (i + 0.5));
}
for (i = 0; i < 64; i++) {
k = fftorder[i] / 4;
pre2[i].real = cos ((M_PI / 128) * (k - 0.25));
pre2[i].imag = sin ((M_PI / 128) * (k - 0.25));
}
for (i = 0; i < 32; i++) {
post2[i].real = cos ((M_PI / 128) * (i + 0.5));
post2[i].imag = sin ((M_PI / 128) * (i + 0.5));
}
#ifdef LIBA52_DJBFFT
if (mm_accel & MM_ACCEL_DJBFFT) {
fprintf (stderr, "Using djbfft for IMDCT transform\n");
ifft128 = (void (*) (complex_t *)) fftc4_un128;
ifft64 = (void (*) (complex_t *)) fftc4_un64;
} else
#endif
{
fprintf (stderr, "No accelerated IMDCT transform found\n");
ifft128 = ifft128_c;
ifft64 = ifft64_c;
}
}

View File

@ -0,0 +1,13 @@
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
#ifdef ARCH_X86
typedef signed long long int64_t;
#endif
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#ifdef ARCH_X86
typedef unsigned long long uint64_t;
#endif

View File

@ -0,0 +1,37 @@
/*
* mm_accel.h
* Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of a52dec, a free ATSC A-52 stream decoder.
* See http://liba52.sourceforge.net/ for updates.
*
* a52dec 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.
*
* a52dec is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MM_ACCEL_H
#define MM_ACCEL_H
/* generic accelerations */
#define MM_ACCEL_DJBFFT 0x00000001
/* x86 accelerations */
#define MM_ACCEL_X86_MMX 0x80000000
#define MM_ACCEL_X86_3DNOW 0x40000000
#define MM_ACCEL_X86_MMXEXT 0x20000000
uint32_t mm_accel (void);
#endif /* MM_ACCEL_H */

View File

@ -0,0 +1,903 @@
/*
* parse.c
* Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of a52dec, a free ATSC A-52 stream decoder.
* See http://liba52.sourceforge.net/ for updates.
*
* a52dec 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.
*
* a52dec is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma warning(disable:4305)
#pragma warning(disable:4244)
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "inttypes.h"
#include "a52.h"
#include "a52_internal.h"
#include "bitstream.h"
#include "tables.h"
#ifdef HAVE_MEMALIGN
/* some systems have memalign() but no declaration for it */
void * memalign (size_t align, size_t size);
#else
/* assume malloc alignment is sufficient */
#define memalign(align,size) malloc (size)
#endif
typedef struct {
sample_t q1[2];
sample_t q2[2];
sample_t q4;
int q1_ptr;
int q2_ptr;
int q4_ptr;
} quantizer_t;
static uint8_t halfrate[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3};
a52_state_t * a52_init (uint32_t mm_accel)
{
a52_state_t * state;
int i;
state = malloc (sizeof (a52_state_t));
if (state == NULL)
return NULL;
state->samples = memalign (16, 256 * 12 * sizeof (sample_t));
if (state->samples == NULL) {
free (state);
return NULL;
}
for (i = 0; i < 256 * 12; i++)
state->samples[i] = 0;
state->downmixed = 1;
state->lfsr_state = 1;
a52_imdct_init (mm_accel);
return state;
}
sample_t * a52_samples (a52_state_t * state)
{
return state->samples;
}
int a52_syncinfo (uint8_t * buf, int * flags,
int * sample_rate, int * bit_rate)
{
static int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112,
128, 160, 192, 224, 256, 320, 384, 448,
512, 576, 640};
static uint8_t lfeon[8] = {0x10, 0x10, 0x04, 0x04, 0x04, 0x01, 0x04, 0x01};
int frmsizecod;
int bitrate;
int half;
int acmod;
if ((buf[0] != 0x0b) || (buf[1] != 0x77)) /* syncword */
return 0;
if (buf[5] >= 0x60) /* bsid >= 12 */
return 0;
half = halfrate[buf[5] >> 3];
/* acmod, dsurmod and lfeon */
acmod = buf[6] >> 5;
*flags = ((((buf[6] & 0xf8) == 0x50) ? A52_DOLBY : acmod) |
((buf[6] & lfeon[acmod]) ? A52_LFE : 0));
frmsizecod = buf[4] & 63;
if (frmsizecod >= 38)
return 0;
bitrate = rate [frmsizecod >> 1];
*bit_rate = (bitrate * 1000) >> half;
switch (buf[4] & 0xc0) {
case 0:
*sample_rate = 48000 >> half;
return 4 * bitrate;
case 0x40:
*sample_rate = 44100 >> half;
return 2 * (320 * bitrate / 147 + (frmsizecod & 1));
case 0x80:
*sample_rate = 32000 >> half;
return 6 * bitrate;
default:
return 0;
}
}
int a52_frame (a52_state_t * state, uint8_t * buf, int * flags,
sample_t * level, sample_t bias)
{
static sample_t clev[4] = {LEVEL_3DB, LEVEL_45DB, LEVEL_6DB, LEVEL_45DB};
static sample_t slev[4] = {LEVEL_3DB, LEVEL_6DB, 0, LEVEL_6DB};
int chaninfo;
int acmod;
state->fscod = buf[4] >> 6;
state->halfrate = halfrate[buf[5] >> 3];
state->acmod = acmod = buf[6] >> 5;
a52_bitstream_set_ptr (state, buf + 6);
bitstream_get (state, 3); /* skip acmod we already parsed */
if ((acmod == 2) && (bitstream_get (state, 2) == 2)) /* dsurmod */
acmod = A52_DOLBY;
if ((acmod & 1) && (acmod != 1))
state->clev = clev[bitstream_get (state, 2)]; /* cmixlev */
if (acmod & 4)
state->slev = slev[bitstream_get (state, 2)]; /* surmixlev */
state->lfeon = bitstream_get (state, 1);
state->output = a52_downmix_init (acmod, *flags, level,
state->clev, state->slev);
if (state->output < 0)
return 1;
if (state->lfeon && (*flags & A52_LFE))
state->output |= A52_LFE;
*flags = state->output;
/* the 2* compensates for differences in imdct */
state->dynrng = state->level = 2 * *level;
state->bias = bias;
state->dynrnge = 1;
state->dynrngcall = NULL;
state->cplba.deltbae = DELTA_BIT_NONE;
state->ba[0].deltbae = state->ba[1].deltbae = state->ba[2].deltbae =
state->ba[3].deltbae = state->ba[4].deltbae = DELTA_BIT_NONE;
chaninfo = !acmod;
do {
bitstream_get (state, 5); /* dialnorm */
if (bitstream_get (state, 1)) /* compre */
bitstream_get (state, 8); /* compr */
if (bitstream_get (state, 1)) /* langcode */
bitstream_get (state, 8); /* langcod */
if (bitstream_get (state, 1)) /* audprodie */
bitstream_get (state, 7); /* mixlevel + roomtyp */
} while (chaninfo--);
bitstream_get (state, 2); /* copyrightb + origbs */
if (bitstream_get (state, 1)) /* timecod1e */
bitstream_get (state, 14); /* timecod1 */
if (bitstream_get (state, 1)) /* timecod2e */
bitstream_get (state, 14); /* timecod2 */
if (bitstream_get (state, 1)) { /* addbsie */
int addbsil;
addbsil = bitstream_get (state, 6);
do {
bitstream_get (state, 8); /* addbsi */
} while (addbsil--);
}
return 0;
}
void a52_dynrng (a52_state_t * state,
sample_t (* call) (sample_t, void *), void * data)
{
state->dynrnge = 0;
if (call) {
state->dynrnge = 1;
state->dynrngcall = call;
state->dynrngdata = data;
}
}
static int parse_exponents (a52_state_t * state, int expstr, int ngrps,
uint8_t exponent, uint8_t * dest)
{
int exps;
while (ngrps--) {
exps = bitstream_get (state, 7);
exponent += exp_1[exps];
if (exponent > 24)
return 1;
switch (expstr) {
case EXP_D45:
*(dest++) = exponent;
*(dest++) = exponent;
case EXP_D25:
*(dest++) = exponent;
case EXP_D15:
*(dest++) = exponent;
}
exponent += exp_2[exps];
if (exponent > 24)
return 1;
switch (expstr) {
case EXP_D45:
*(dest++) = exponent;
*(dest++) = exponent;
case EXP_D25:
*(dest++) = exponent;
case EXP_D15:
*(dest++) = exponent;
}
exponent += exp_3[exps];
if (exponent > 24)
return 1;
switch (expstr) {
case EXP_D45:
*(dest++) = exponent;
*(dest++) = exponent;
case EXP_D25:
*(dest++) = exponent;
case EXP_D15:
*(dest++) = exponent;
}
}
return 0;
}
static int parse_deltba (a52_state_t * state, int8_t * deltba)
{
int deltnseg, deltlen, delta, j;
memset (deltba, 0, 50);
deltnseg = bitstream_get (state, 3);
j = 0;
do {
j += bitstream_get (state, 5);
deltlen = bitstream_get (state, 4);
delta = bitstream_get (state, 3);
delta -= (delta >= 4) ? 3 : 4;
if (!deltlen)
continue;
if (j + deltlen >= 50)
return 1;
while (deltlen--)
deltba[j++] = delta;
} while (deltnseg--);
return 0;
}
static inline int zero_snr_offsets (int nfchans, a52_state_t * state)
{
int i;
if ((state->csnroffst) ||
(state->chincpl && state->cplba.bai >> 3) || /* cplinu, fsnroffst */
(state->lfeon && state->lfeba.bai >> 3)) /* fsnroffst */
return 0;
for (i = 0; i < nfchans; i++)
if (state->ba[i].bai >> 3) /* fsnroffst */
return 0;
return 1;
}
static inline int16_t dither_gen (a52_state_t * state)
{
int16_t nstate;
nstate = dither_lut[state->lfsr_state >> 8] ^ (state->lfsr_state << 8);
state->lfsr_state = (uint16_t) nstate;
return nstate;
}
static void coeff_get (a52_state_t * state, sample_t * coeff,
expbap_t * expbap, quantizer_t * quantizer,
sample_t level, int dither, int end)
{
int i;
uint8_t * exp;
int8_t * bap;
sample_t factor[25];
for (i = 0; i <= 24; i++)
factor[i] = scale_factor[i] * level;
exp = expbap->exp;
bap = expbap->bap;
for (i = 0; i < end; i++) {
int bapi;
bapi = bap[i];
switch (bapi) {
case 0:
if (dither) {
coeff[i] = dither_gen (state) * LEVEL_3DB * factor[exp[i]];
continue;
} else {
coeff[i] = 0;
continue;
}
case -1:
if (quantizer->q1_ptr >= 0) {
coeff[i] = quantizer->q1[quantizer->q1_ptr--] * factor[exp[i]];
continue;
} else {
int code;
code = bitstream_get (state, 5);
quantizer->q1_ptr = 1;
quantizer->q1[0] = q_1_2[code];
quantizer->q1[1] = q_1_1[code];
coeff[i] = q_1_0[code] * factor[exp[i]];
continue;
}
case -2:
if (quantizer->q2_ptr >= 0) {
coeff[i] = quantizer->q2[quantizer->q2_ptr--] * factor[exp[i]];
continue;
} else {
int code;
code = bitstream_get (state, 7);
quantizer->q2_ptr = 1;
quantizer->q2[0] = q_2_2[code];
quantizer->q2[1] = q_2_1[code];
coeff[i] = q_2_0[code] * factor[exp[i]];
continue;
}
case 3:
coeff[i] = q_3[bitstream_get (state, 3)] * factor[exp[i]];
continue;
case -3:
if (quantizer->q4_ptr == 0) {
quantizer->q4_ptr = -1;
coeff[i] = quantizer->q4 * factor[exp[i]];
continue;
} else {
int code;
code = bitstream_get (state, 7);
quantizer->q4_ptr = 0;
quantizer->q4 = q_4_1[code];
coeff[i] = q_4_0[code] * factor[exp[i]];
continue;
}
case 4:
coeff[i] = q_5[bitstream_get (state, 4)] * factor[exp[i]];
continue;
default:
coeff[i] = ((bitstream_get_2 (state, bapi) << (16 - bapi)) *
factor[exp[i]]);
}
}
}
static void coeff_get_coupling (a52_state_t * state, int nfchans,
sample_t * coeff, sample_t (* samples)[256],
quantizer_t * quantizer, uint8_t dithflag[5])
{
int cplbndstrc, bnd, i, i_end, ch;
uint8_t * exp;
int8_t * bap;
sample_t cplco[5];
exp = state->cpl_expbap.exp;
bap = state->cpl_expbap.bap;
bnd = 0;
cplbndstrc = state->cplbndstrc;
i = state->cplstrtmant;
while (i < state->cplendmant) {
i_end = i + 12;
while (cplbndstrc & 1) {
cplbndstrc >>= 1;
i_end += 12;
}
cplbndstrc >>= 1;
for (ch = 0; ch < nfchans; ch++)
cplco[ch] = state->cplco[ch][bnd] * coeff[ch];
bnd++;
while (i < i_end) {
sample_t cplcoeff;
int bapi;
bapi = bap[i];
switch (bapi) {
case 0:
cplcoeff = LEVEL_3DB * scale_factor[exp[i]];
for (ch = 0; ch < nfchans; ch++)
if ((state->chincpl >> ch) & 1) {
if (dithflag[ch])
samples[ch][i] = (cplcoeff * cplco[ch] *
dither_gen (state));
else
samples[ch][i] = 0;
}
i++;
continue;
case -1:
if (quantizer->q1_ptr >= 0) {
cplcoeff = quantizer->q1[quantizer->q1_ptr--];
break;
} else {
int code;
code = bitstream_get (state, 5);
quantizer->q1_ptr = 1;
quantizer->q1[0] = q_1_2[code];
quantizer->q1[1] = q_1_1[code];
cplcoeff = q_1_0[code];
break;
}
case -2:
if (quantizer->q2_ptr >= 0) {
cplcoeff = quantizer->q2[quantizer->q2_ptr--];
break;
} else {
int code;
code = bitstream_get (state, 7);
quantizer->q2_ptr = 1;
quantizer->q2[0] = q_2_2[code];
quantizer->q2[1] = q_2_1[code];
cplcoeff = q_2_0[code];
break;
}
case 3:
cplcoeff = q_3[bitstream_get (state, 3)];
break;
case -3:
if (quantizer->q4_ptr == 0) {
quantizer->q4_ptr = -1;
cplcoeff = quantizer->q4;
break;
} else {
int code;
code = bitstream_get (state, 7);
quantizer->q4_ptr = 0;
quantizer->q4 = q_4_1[code];
cplcoeff = q_4_0[code];
break;
}
case 4:
cplcoeff = q_5[bitstream_get (state, 4)];
break;
default:
cplcoeff = bitstream_get_2 (state, bapi) << (16 - bapi);
}
cplcoeff *= scale_factor[exp[i]];
for (ch = 0; ch < nfchans; ch++)
if ((state->chincpl >> ch) & 1)
samples[ch][i] = cplcoeff * cplco[ch];
i++;
}
}
}
int a52_block (a52_state_t * state)
{
static const uint8_t nfchans_tbl[] = {2, 1, 2, 3, 3, 4, 4, 5, 1, 1, 2};
static int rematrix_band[4] = {25, 37, 61, 253};
int i, nfchans, chaninfo;
uint8_t cplexpstr, chexpstr[5], lfeexpstr, do_bit_alloc, done_cpl;
uint8_t blksw[5], dithflag[5];
sample_t coeff[5];
int chanbias;
quantizer_t quantizer;
sample_t * samples;
nfchans = nfchans_tbl[state->acmod];
for (i = 0; i < nfchans; i++)
blksw[i] = bitstream_get (state, 1);
for (i = 0; i < nfchans; i++)
dithflag[i] = bitstream_get (state, 1);
chaninfo = !state->acmod;
do {
if (bitstream_get (state, 1)) { /* dynrnge */
int dynrng;
dynrng = bitstream_get_2 (state, 8);
if (state->dynrnge) {
sample_t range;
range = ((((dynrng & 0x1f) | 0x20) << 13) *
scale_factor[3 - (dynrng >> 5)]);
if (state->dynrngcall)
range = state->dynrngcall (range, state->dynrngdata);
state->dynrng = state->level * range;
}
}
} while (chaninfo--);
if (bitstream_get (state, 1)) { /* cplstre */
state->chincpl = 0;
if (bitstream_get (state, 1)) { /* cplinu */
static uint8_t bndtab[16] = {31, 35, 37, 39, 41, 42, 43, 44,
45, 45, 46, 46, 47, 47, 48, 48};
int cplbegf;
int cplendf;
int ncplsubnd;
for (i = 0; i < nfchans; i++)
state->chincpl |= bitstream_get (state, 1) << i;
switch (state->acmod) {
case 0: case 1:
return 1;
case 2:
state->phsflginu = bitstream_get (state, 1);
}
cplbegf = bitstream_get (state, 4);
cplendf = bitstream_get (state, 4);
if (cplendf + 3 - cplbegf < 0)
return 1;
state->ncplbnd = ncplsubnd = cplendf + 3 - cplbegf;
state->cplstrtbnd = bndtab[cplbegf];
state->cplstrtmant = cplbegf * 12 + 37;
state->cplendmant = cplendf * 12 + 73;
state->cplbndstrc = 0;
for (i = 0; i < ncplsubnd - 1; i++)
if (bitstream_get (state, 1)) {
state->cplbndstrc |= 1 << i;
state->ncplbnd--;
}
}
}
if (state->chincpl) { /* cplinu */
int j, cplcoe;
cplcoe = 0;
for (i = 0; i < nfchans; i++)
if ((state->chincpl) >> i & 1)
if (bitstream_get (state, 1)) { /* cplcoe */
int mstrcplco, cplcoexp, cplcomant;
cplcoe = 1;
mstrcplco = 3 * bitstream_get (state, 2);
for (j = 0; j < state->ncplbnd; j++) {
cplcoexp = bitstream_get (state, 4);
cplcomant = bitstream_get (state, 4);
if (cplcoexp == 15)
cplcomant <<= 14;
else
cplcomant = (cplcomant | 0x10) << 13;
state->cplco[i][j] =
cplcomant * scale_factor[cplcoexp + mstrcplco];
}
}
if ((state->acmod == 2) && state->phsflginu && cplcoe)
for (j = 0; j < state->ncplbnd; j++)
if (bitstream_get (state, 1)) /* phsflg */
state->cplco[1][j] = -state->cplco[1][j];
}
if ((state->acmod == 2) && (bitstream_get (state, 1))) { /* rematstr */
int end;
state->rematflg = 0;
end = (state->chincpl) ? state->cplstrtmant : 253; /* cplinu */
i = 0;
do
state->rematflg |= bitstream_get (state, 1) << i;
while (rematrix_band[i++] < end);
}
cplexpstr = EXP_REUSE;
lfeexpstr = EXP_REUSE;
if (state->chincpl) /* cplinu */
cplexpstr = bitstream_get (state, 2);
for (i = 0; i < nfchans; i++)
chexpstr[i] = bitstream_get (state, 2);
if (state->lfeon)
lfeexpstr = bitstream_get (state, 1);
for (i = 0; i < nfchans; i++)
if (chexpstr[i] != EXP_REUSE) {
if ((state->chincpl >> i) & 1)
state->endmant[i] = state->cplstrtmant;
else {
int chbwcod;
chbwcod = bitstream_get (state, 6);
if (chbwcod > 60)
return 1;
state->endmant[i] = chbwcod * 3 + 73;
}
}
do_bit_alloc = 0;
if (cplexpstr != EXP_REUSE) {
int cplabsexp, ncplgrps;
do_bit_alloc = 64;
ncplgrps = ((state->cplendmant - state->cplstrtmant) /
(3 << (cplexpstr - 1)));
cplabsexp = bitstream_get (state, 4) << 1;
if (parse_exponents (state, cplexpstr, ncplgrps, cplabsexp,
state->cpl_expbap.exp + state->cplstrtmant))
return 1;
}
for (i = 0; i < nfchans; i++)
if (chexpstr[i] != EXP_REUSE) {
int grp_size, nchgrps;
do_bit_alloc |= 1 << i;
grp_size = 3 << (chexpstr[i] - 1);
nchgrps = (state->endmant[i] + grp_size - 4) / grp_size;
state->fbw_expbap[i].exp[0] = bitstream_get (state, 4);
if (parse_exponents (state, chexpstr[i], nchgrps,
state->fbw_expbap[i].exp[0],
state->fbw_expbap[i].exp + 1))
return 1;
bitstream_get (state, 2); /* gainrng */
}
if (lfeexpstr != EXP_REUSE) {
do_bit_alloc |= 32;
state->lfe_expbap.exp[0] = bitstream_get (state, 4);
if (parse_exponents (state, lfeexpstr, 2, state->lfe_expbap.exp[0],
state->lfe_expbap.exp + 1))
return 1;
}
if (bitstream_get (state, 1)) { /* baie */
do_bit_alloc = -1;
state->bai = bitstream_get (state, 11);
}
if (bitstream_get (state, 1)) { /* snroffste */
do_bit_alloc = -1;
state->csnroffst = bitstream_get (state, 6);
if (state->chincpl) /* cplinu */
state->cplba.bai = bitstream_get (state, 7);
for (i = 0; i < nfchans; i++)
state->ba[i].bai = bitstream_get (state, 7);
if (state->lfeon)
state->lfeba.bai = bitstream_get (state, 7);
}
if ((state->chincpl) && (bitstream_get (state, 1))) { /* cplleake */
do_bit_alloc |= 64;
state->cplfleak = 9 - bitstream_get (state, 3);
state->cplsleak = 9 - bitstream_get (state, 3);
}
if (bitstream_get (state, 1)) { /* deltbaie */
do_bit_alloc = -1;
if (state->chincpl) /* cplinu */
state->cplba.deltbae = bitstream_get (state, 2);
for (i = 0; i < nfchans; i++)
state->ba[i].deltbae = bitstream_get (state, 2);
if (state->chincpl && /* cplinu */
(state->cplba.deltbae == DELTA_BIT_NEW) &&
parse_deltba (state, state->cplba.deltba))
return 1;
for (i = 0; i < nfchans; i++)
if ((state->ba[i].deltbae == DELTA_BIT_NEW) &&
parse_deltba (state, state->ba[i].deltba))
return 1;
}
if (do_bit_alloc) {
if (zero_snr_offsets (nfchans, state)) {
memset (state->cpl_expbap.bap, 0, sizeof (state->cpl_expbap.bap));
for (i = 0; i < nfchans; i++)
memset (state->fbw_expbap[i].bap, 0,
sizeof (state->fbw_expbap[i].bap));
memset (state->lfe_expbap.bap, 0, sizeof (state->lfe_expbap.bap));
} else {
if (state->chincpl && (do_bit_alloc & 64)) /* cplinu */
a52_bit_allocate (state, &state->cplba, state->cplstrtbnd,
state->cplstrtmant, state->cplendmant,
state->cplfleak << 8, state->cplsleak << 8,
&state->cpl_expbap);
for (i = 0; i < nfchans; i++)
if (do_bit_alloc & (1 << i))
a52_bit_allocate (state, state->ba + i, 0, 0,
state->endmant[i], 0, 0,
state->fbw_expbap +i);
if (state->lfeon && (do_bit_alloc & 32)) {
state->lfeba.deltbae = DELTA_BIT_NONE;
a52_bit_allocate (state, &state->lfeba, 0, 0, 7, 0, 0,
&state->lfe_expbap);
}
}
}
if (bitstream_get (state, 1)) { /* skiple */
i = bitstream_get (state, 9); /* skipl */
while (i--)
bitstream_get (state, 8);
}
samples = state->samples;
if (state->output & A52_LFE)
samples += 256; /* shift for LFE channel */
chanbias = a52_downmix_coeff (coeff, state->acmod, state->output,
state->dynrng, state->clev, state->slev);
quantizer.q1_ptr = quantizer.q2_ptr = quantizer.q4_ptr = -1;
done_cpl = 0;
for (i = 0; i < nfchans; i++) {
int j;
coeff_get (state, samples + 256 * i, state->fbw_expbap +i, &quantizer,
coeff[i], dithflag[i], state->endmant[i]);
if ((state->chincpl >> i) & 1) {
if (!done_cpl) {
done_cpl = 1;
coeff_get_coupling (state, nfchans, coeff,
(sample_t (*)[256])samples, &quantizer,
dithflag);
}
j = state->cplendmant;
} else
j = state->endmant[i];
do
(samples + 256 * i)[j] = 0;
while (++j < 256);
}
if (state->acmod == 2) {
int j, end, band, rematflg;
end = ((state->endmant[0] < state->endmant[1]) ?
state->endmant[0] : state->endmant[1]);
i = 0;
j = 13;
rematflg = state->rematflg;
do {
if (! (rematflg & 1)) {
rematflg >>= 1;
j = rematrix_band[i++];
continue;
}
rematflg >>= 1;
band = rematrix_band[i++];
if (band > end)
band = end;
do {
sample_t tmp0, tmp1;
tmp0 = samples[j];
tmp1 = (samples+256)[j];
samples[j] = tmp0 + tmp1;
(samples+256)[j] = tmp0 - tmp1;
} while (++j < band);
} while (j < end);
}
if (state->lfeon) {
if (state->output & A52_LFE) {
coeff_get (state, samples - 256, &state->lfe_expbap, &quantizer,
state->dynrng, 0, 7);
for (i = 7; i < 256; i++)
(samples-256)[i] = 0;
a52_imdct_512 (samples - 256, samples + 1536 - 256, state->bias);
} else {
/* just skip the LFE coefficients */
coeff_get (state, samples + 1280, &state->lfe_expbap, &quantizer,
0, 0, 7);
}
}
i = 0;
if (nfchans_tbl[state->output & A52_CHANNEL_MASK] < nfchans)
for (i = 1; i < nfchans; i++)
if (blksw[i] != blksw[0])
break;
if (i < nfchans) {
if (state->downmixed) {
state->downmixed = 0;
a52_upmix (samples + 1536, state->acmod, state->output);
}
for (i = 0; i < nfchans; i++) {
sample_t bias;
bias = 0;
if (!(chanbias & (1 << i)))
bias = state->bias;
if (coeff[i]) {
if (blksw[i])
a52_imdct_256 (samples + 256 * i, samples + 1536 + 256 * i,
bias);
else
a52_imdct_512 (samples + 256 * i, samples + 1536 + 256 * i,
bias);
} else {
int j;
for (j = 0; j < 256; j++)
(samples + 256 * i)[j] = bias;
}
}
a52_downmix (samples, state->acmod, state->output, state->bias,
state->clev, state->slev);
} else {
nfchans = nfchans_tbl[state->output & A52_CHANNEL_MASK];
a52_downmix (samples, state->acmod, state->output, 0,
state->clev, state->slev);
if (!state->downmixed) {
state->downmixed = 1;
a52_downmix (samples + 1536, state->acmod, state->output, 0,
state->clev, state->slev);
}
if (blksw[0])
for (i = 0; i < nfchans; i++)
a52_imdct_256 (samples + 256 * i, samples + 1536 + 256 * i,
state->bias);
else
for (i = 0; i < nfchans; i++)
a52_imdct_512 (samples + 256 * i, samples + 1536 + 256 * i,
state->bias);
}
return 0;
}
void a52_free (a52_state_t * state)
{
free (state->samples);
free (state);
}

View File

@ -0,0 +1,246 @@
/*
* tables.h
* Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of a52dec, a free ATSC A-52 stream decoder.
* See http://liba52.sourceforge.net/ for updates.
*
* a52dec 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.
*
* a52dec is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
static const int8_t exp_1[128] = {
-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
25,25,25
};
static const int8_t exp_2[128] = {
-2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
-2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
-2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
-2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
-2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
25,25,25
};
static const int8_t exp_3[128] = {
-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,
-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,
-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,
-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,
-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,
25,25,25
};
#define Q0 ((-2 << 15) / 3.0)
#define Q1 (0)
#define Q2 ((2 << 15) / 3.0)
static const sample_t q_1_0[32] = {
Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,
Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,
Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,
0,0,0,0,0
};
static const sample_t q_1_1[32] = {
Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2,
Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2,
Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2,
0,0,0,0,0
};
static const sample_t q_1_2[32] = {
Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2,
Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2,
Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2,
0,0,0,0,0
};
#undef Q0
#undef Q1
#undef Q2
#define Q0 ((-4 << 15) / 5.0)
#define Q1 ((-2 << 15) / 5.0)
#define Q2 (0)
#define Q3 ((2 << 15) / 5.0)
#define Q4 ((4 << 15) / 5.0)
static const sample_t q_2_0[128] = {
Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,
Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,
Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,
Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,
Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,
0,0,0
};
static const sample_t q_2_1[128] = {
Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4,
Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4,
Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4,
Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4,
Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4,
0,0,0
};
static const sample_t q_2_2[128] = {
Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,
Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,
Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,
Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,
Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,
0,0,0
};
#undef Q0
#undef Q1
#undef Q2
#undef Q3
#undef Q4
static const sample_t q_3[8] = {
(-6 << 15)/7.0, (-4 << 15)/7.0, (-2 << 15)/7.0, 0,
( 2 << 15)/7.0, ( 4 << 15)/7.0, ( 6 << 15)/7.0, 0
};
#define Q0 ((-10 << 15) / 11.0)
#define Q1 ((-8 << 15) / 11.0)
#define Q2 ((-6 << 15) / 11.0)
#define Q3 ((-4 << 15) / 11.0)
#define Q4 ((-2 << 15) / 11.0)
#define Q5 (0)
#define Q6 ((2 << 15) / 11.0)
#define Q7 ((4 << 15) / 11.0)
#define Q8 ((6 << 15) / 11.0)
#define Q9 ((8 << 15) / 11.0)
#define QA ((10 << 15) / 11.0)
static const sample_t q_4_0[128] = {
Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0,
Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1,
Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2,
Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3,
Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4,
Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5,
Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6,
Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7,
Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8,
Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9,
QA, QA, QA, QA, QA, QA, QA, QA, QA, QA, QA,
0, 0, 0, 0, 0, 0, 0
};
static const sample_t q_4_1[128] = {
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
0, 0, 0, 0, 0, 0, 0
};
#undef Q0
#undef Q1
#undef Q2
#undef Q3
#undef Q4
#undef Q5
#undef Q6
#undef Q7
#undef Q8
#undef Q9
#undef QA
static const sample_t q_5[16] = {
(-14 << 15)/15.0,(-12 << 15)/15.0,(-10 << 15)/15.0,
( -8 << 15)/15.0,( -6 << 15)/15.0,( -4 << 15)/15.0,
( -2 << 15)/15.0, 0 ,( 2 << 15)/15.0,
( 4 << 15)/15.0,( 6 << 15)/15.0,( 8 << 15)/15.0,
( 10 << 15)/15.0,( 12 << 15)/15.0,( 14 << 15)/15.0,
0
};
static const sample_t scale_factor[25] = {
0.000030517578125,
0.0000152587890625,
0.00000762939453125,
0.000003814697265625,
0.0000019073486328125,
0.00000095367431640625,
0.000000476837158203125,
0.0000002384185791015625,
0.00000011920928955078125,
0.000000059604644775390625,
0.0000000298023223876953125,
0.00000001490116119384765625,
0.000000007450580596923828125,
0.0000000037252902984619140625,
0.00000000186264514923095703125,
0.000000000931322574615478515625,
0.0000000004656612873077392578125,
0.00000000023283064365386962890625,
0.000000000116415321826934814453125,
0.0000000000582076609134674072265625,
0.00000000002910383045673370361328125,
0.000000000014551915228366851806640625,
0.0000000000072759576141834259033203125,
0.00000000000363797880709171295166015625,
0.000000000001818989403545856475830078125
};
static const uint16_t dither_lut[256] = {
0x0000, 0xa011, 0xe033, 0x4022, 0x6077, 0xc066, 0x8044, 0x2055,
0xc0ee, 0x60ff, 0x20dd, 0x80cc, 0xa099, 0x0088, 0x40aa, 0xe0bb,
0x21cd, 0x81dc, 0xc1fe, 0x61ef, 0x41ba, 0xe1ab, 0xa189, 0x0198,
0xe123, 0x4132, 0x0110, 0xa101, 0x8154, 0x2145, 0x6167, 0xc176,
0x439a, 0xe38b, 0xa3a9, 0x03b8, 0x23ed, 0x83fc, 0xc3de, 0x63cf,
0x8374, 0x2365, 0x6347, 0xc356, 0xe303, 0x4312, 0x0330, 0xa321,
0x6257, 0xc246, 0x8264, 0x2275, 0x0220, 0xa231, 0xe213, 0x4202,
0xa2b9, 0x02a8, 0x428a, 0xe29b, 0xc2ce, 0x62df, 0x22fd, 0x82ec,
0x8734, 0x2725, 0x6707, 0xc716, 0xe743, 0x4752, 0x0770, 0xa761,
0x47da, 0xe7cb, 0xa7e9, 0x07f8, 0x27ad, 0x87bc, 0xc79e, 0x678f,
0xa6f9, 0x06e8, 0x46ca, 0xe6db, 0xc68e, 0x669f, 0x26bd, 0x86ac,
0x6617, 0xc606, 0x8624, 0x2635, 0x0660, 0xa671, 0xe653, 0x4642,
0xc4ae, 0x64bf, 0x249d, 0x848c, 0xa4d9, 0x04c8, 0x44ea, 0xe4fb,
0x0440, 0xa451, 0xe473, 0x4462, 0x6437, 0xc426, 0x8404, 0x2415,
0xe563, 0x4572, 0x0550, 0xa541, 0x8514, 0x2505, 0x6527, 0xc536,
0x258d, 0x859c, 0xc5be, 0x65af, 0x45fa, 0xe5eb, 0xa5c9, 0x05d8,
0xae79, 0x0e68, 0x4e4a, 0xee5b, 0xce0e, 0x6e1f, 0x2e3d, 0x8e2c,
0x6e97, 0xce86, 0x8ea4, 0x2eb5, 0x0ee0, 0xaef1, 0xeed3, 0x4ec2,
0x8fb4, 0x2fa5, 0x6f87, 0xcf96, 0xefc3, 0x4fd2, 0x0ff0, 0xafe1,
0x4f5a, 0xef4b, 0xaf69, 0x0f78, 0x2f2d, 0x8f3c, 0xcf1e, 0x6f0f,
0xede3, 0x4df2, 0x0dd0, 0xadc1, 0x8d94, 0x2d85, 0x6da7, 0xcdb6,
0x2d0d, 0x8d1c, 0xcd3e, 0x6d2f, 0x4d7a, 0xed6b, 0xad49, 0x0d58,
0xcc2e, 0x6c3f, 0x2c1d, 0x8c0c, 0xac59, 0x0c48, 0x4c6a, 0xec7b,
0x0cc0, 0xacd1, 0xecf3, 0x4ce2, 0x6cb7, 0xcca6, 0x8c84, 0x2c95,
0x294d, 0x895c, 0xc97e, 0x696f, 0x493a, 0xe92b, 0xa909, 0x0918,
0xe9a3, 0x49b2, 0x0990, 0xa981, 0x89d4, 0x29c5, 0x69e7, 0xc9f6,
0x0880, 0xa891, 0xe8b3, 0x48a2, 0x68f7, 0xc8e6, 0x88c4, 0x28d5,
0xc86e, 0x687f, 0x285d, 0x884c, 0xa819, 0x0808, 0x482a, 0xe83b,
0x6ad7, 0xcac6, 0x8ae4, 0x2af5, 0x0aa0, 0xaab1, 0xea93, 0x4a82,
0xaa39, 0x0a28, 0x4a0a, 0xea1b, 0xca4e, 0x6a5f, 0x2a7d, 0x8a6c,
0x4b1a, 0xeb0b, 0xab29, 0x0b38, 0x2b6d, 0x8b7c, 0xcb5e, 0x6b4f,
0x8bf4, 0x2be5, 0x6bc7, 0xcbd6, 0xeb83, 0x4b92, 0x0bb0, 0xaba1
};

View File

@ -0,0 +1,35 @@
/*
* tendra.h
* Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of a52dec, a free ATSC A-52 stream decoder.
* See http://liba52.sourceforge.net/ for updates.
*
* a52dec 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.
*
* a52dec is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma TenDRA begin
#pragma TenDRA longlong type warning
#ifdef TenDRA_check
#pragma TenDRA conversion analysis (pointer-int explicit) off
#pragma TenDRA implicit function declaration off
/* avoid the "No declarations in translation unit" problem */
int TenDRA;
#endif /* TenDRA_check */

View File

@ -0,0 +1,67 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#include "lowpass.h"
#include <math.h>
#include <float.h>
void LPF_init(LPF_data*lpf,double freq, double srate)
{
double omega = 2*freq/srate;
double g = 1.0;
// calculating coefficients:
double k,p,q,a;
double a0,a1,a2,a3,a4;
k=(4.0*g-3.0)/(g+1.0);
p=1.0-0.25*k;p*=p;
// LP:
a=1.0/(tan(0.5*omega)*(1.0+p));
p=1.0+a;
q=1.0-a;
a0=1.0/(k+p*p*p*p);
a1=4.0*(k+p*p*p*q);
a2=6.0*(k+p*p*q*q);
a3=4.0*(k+p*q*q*q);
a4= (k+q*q*q*q);
p=a0*(k+1.0);
lpf->coef[0]=p;
lpf->coef[1]=4.0*p;
lpf->coef[2]=6.0*p;
lpf->coef[3]=4.0*p;
lpf->coef[4]=p;
lpf->coef[5]=-a1*a0;
lpf->coef[6]=-a2*a0;
lpf->coef[7]=-a3*a0;
lpf->coef[8]=-a4*a0;
}
double LPF(LPF_data* lpf, double in)
{
// per sample:
double out=lpf->coef[0]*in+lpf->d[0];
lpf->d[0] =lpf->coef[1]*in+lpf->coef[5]*out+lpf->d[1];
lpf->d[1] =lpf->coef[2]*in+lpf->coef[6]*out+lpf->d[2];
lpf->d[2] =lpf->coef[3]*in+lpf->coef[7]*out+lpf->d[3];
lpf->d[3] =lpf->coef[4]*in+lpf->coef[8]*out;
return out;
}

27
plugins/spu2ghz/lowpass.h Normal file
View File

@ -0,0 +1,27 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#pragma once
typedef struct IIR_data
{
double coef[9];
double d[4];
} LPF_data;
void LPF_init(LPF_data*lpf,double freq, double srate);
double LPF(LPF_data* lpf, double in);

1156
plugins/spu2ghz/mixer.cpp Normal file

File diff suppressed because it is too large Load Diff

27
plugins/spu2ghz/mixer.h Normal file
View File

@ -0,0 +1,27 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#ifndef MIXER_H_INCLUDED
#define MIXER_H_INCLUDED
void __fastcall Mix();
void __fastcall LogVolInit();
void __fastcall LogVolClose();
#endif // MIXER_H_INCLUDED //

View File

@ -0,0 +1,39 @@
@echo off
echo Configuring...
set RAREXE="C:\Program Files (x86)\WinRAR\rar.exe"
echo Checking files...
if not exist %RAREXE% goto error_1
if not exist .\bin\spu2ghz.dll goto error_2
if not exist .\changelog.txt goto error_3
echo Preparing files...
copy changelog.txt .\bin\
cd bin
echo Packing...
if exist spu2ghz.rar del spu2ghz.rar
%RAREXE% a -m5 spu2ghz.rar spu2ghz.dll changelog.txt >null
if errorlevel 1 (
echo ERROR: %rarexe% returned an error code.
exit 4
)
echo Finished.
exit
:error_1
echo ERROR: Cannot find the rar executable. Change %0 to point it to rar.exe.
exit /B 1
:error_2
echo ERROR: Cannot find spu2ghz.dll
exit /B 2
:error_3
echo ERROR: Cannot find changelog.txt
exit /B 3

184
plugins/spu2ghz/regs.h Normal file
View File

@ -0,0 +1,184 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#ifndef REGS_H_INCLUDED
#define REGS_H_INCLUDED
#define SPU2_CORE0 0x00000000
#define SPU2_CORE1 0x00000400
#define SPU2_VP(voice) ((voice) * 16)
#define SPU2_VA(voice) ((voice) * 12)
#define REG_VP_VOLL 0x0000 // Voice Volume Left
#define REG_VP_VOLR 0x0002 // Voice Volume Right
#define REG_VP_PITCH 0x0004 // Pitch
#define REG_VP_ADSR1 0x0006 // Envelope 1 (Attack-Decay-Sustain-Release)
#define REG_VP_ADSR2 0x0008 // Envelope 2 (Attack-Decay-Sustain-Release)
#define REG_VP_ENVX 0x000A // Current Envelope
#define REG_VP_VOLXL 0x000C // Current Voice Volume Left
#define REG_VP_VOLXR 0x000E // Current Voice Volume Right
// .. repeated for each voice ..
#define REG_S_PMON 0x0180 // Pitch Modulation Spec.
#define REG_S_NON 0x0184 // Alloc Noise Generator
#define REG_S_VMIXL 0x0188 // Voice Output Mix Left (Dry)
#define REG_S_VMIXEL 0x018C // Voice Output Mix Left (Wet)
#define REG_S_VMIXR 0x0190 // Voice Output Mix Right (Dry)
#define REG_S_VMIXER 0x0194 // Voice Output Mix Right (Wet)
#define REG_P_MMIX 0x0198 // Output Spec. After Voice Mix
#define REG_C_ATTR 0x019A // Core X Attrib
#define REG_A_IRQA 0x019C // Interrupt Address Spec.
#define REG_S_KON 0x01A0 // Key On 0/1
#define REG_S_KOFF 0x01A4 // Key Off 0/1
#define REG_A_TSA 0x01A8 // Transfer starting address
#define REG__1AC 0x01AC // Transfer data
#define REG__1AE 0x01AE
#define REG_S_ADMAS 0x01B0 // AutoDMA Status
// 1b2, 1b4, 1b6, 1b8, 1ba, 1bc, 1be are unknown
#define REG_VA_SSA 0x01C0 // Waveform data starting address
#define REG_VA_LSAX 0x01C4 // Loop point address
#define REG_VA_NAX 0x01C8 // Waveform data that should be read next
// .. repeated for each voice ..
#define REG_A_ESA 0x02E0 //Address: Top address of working area for effects processing
#define R_FB_SRC_A 0x02E4 // Feedback Source A
#define R_FB_SRC_B 0x02E8 // Feedback Source B
#define R_IIR_DEST_A0 0x02EC
#define R_IIR_DEST_A1 0x02F0
#define R_ACC_SRC_A0 0x02F4
#define R_ACC_SRC_A1 0x02F8
#define R_ACC_SRC_B0 0x02FC
#define R_ACC_SRC_B1 0x0300
#define R_IIR_SRC_A0 0x0304
#define R_IIR_SRC_A1 0x0308
#define R_IIR_DEST_B0 0x030C
#define R_IIR_DEST_B1 0x0310
#define R_ACC_SRC_C0 0x0314
#define R_ACC_SRC_C1 0x0318
#define R_ACC_SRC_D0 0x031C
#define R_ACC_SRC_D1 0x0320
#define R_IIR_SRC_B1 0x0324
#define R_IIR_SRC_B0 0x0328
#define R_MIX_DEST_A0 0x032C
#define R_MIX_DEST_A1 0x0330
#define R_MIX_DEST_B0 0x0334
#define R_MIX_DEST_B1 0x0338
#define REG_A_EEA 0x033C // Address: End address of working area for effects processing (upper part of address only!)
#define REG_S_ENDX 0x0340 // End Point passed flag
#define REG_P_STATX 0x0344 // Status register?
// 0x346 .. 0x3fe are unknown (unused?)
// core 1 has the same registers with 0x400 added.
// core 1 ends at 0x746
// 0x746 .. 0x75e are unknown
// "Different" register area
#define REG_P_MVOLL 0x0760 // Master Volume Left
#define REG_P_MVOLR 0x0762 // Master Volume Right
#define REG_P_EVOLL 0x0764 // Effect Volume Left
#define REG_P_EVOLR 0x0766 // Effect Volume Right
#define REG_P_AVOLL 0x0768 // Core External Input Volume Left (Only Core 1)
#define REG_P_AVOLR 0x076A // Core External Input Volume Right (Only Core 1)
#define REG_P_BVOLL 0x076C // Sound Data Volume Left
#define REG_P_BVOLR 0x076E // Sound Data Volume Right
#define REG_P_MVOLXL 0x0770 // Current Master Volume Left
#define REG_P_MVOLXR 0x0772 // Current Master Volume Right
#define R_IIR_ALPHA 0x0774 //IIR alpha (% used)
#define R_ACC_COEF_A 0x0776
#define R_ACC_COEF_B 0x0778
#define R_ACC_COEF_C 0x077A
#define R_ACC_COEF_D 0x077C
#define R_IIR_COEF 0x077E
#define R_FB_ALPHA 0x0780 //feedback alpha (% used)
#define R_FB_X 0x0782 //feedback
#define R_IN_COEF_L 0x0784
#define R_IN_COEF_R 0x0786
// values repeat for core1
// End OF "Different" register area
// SPDIF interface
#define SPDIF_OUT 0x07C0 // SPDIF Out: OFF/'PCM'/Bitstream/Bypass
#define IRQINFO 0x07C2
#define SPDIF_MODE 0x07C6
#define SPDIF_MEDIA 0x07C8 // SPDIF Media: 'CD'/DVD
#define SPDIF_COPY 0x07CC // SPDIF Copy Protection
/*********************************************************************
Core attributes (SD_C)
bit 1 - Unknown (this bit is sometimes set)
bit 2..3 - Unknown (usually never set)
bit 4..5 - DMA related
bit 6 - IRQ? DMA mode? wtf?
bit 7 - effect enable (reverb enable)
bit 8 - IRQ enable?
bit 9..14 - noise clock
bit 15 - mute
bit 16 - reset
*********************************************************************/
#define SPDIF_OUT_OFF 0x0000 //no spdif output
#define SPDIF_OUT_PCM 0x0020 //encode spdif from spu2 pcm output
#define SPDIF_OUT_BYPASS 0x0100 //bypass spu2 processing
#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 //bypass mode for digital bitstream data
#define SPDIF_MODE_BYPASS_PCM 0x0000 //bypass mode for pcm data (using analog output)
#define SPDIF_MODE_MEDIA_CD 0x0800 //source media is a CD
#define SPDIF_MODE_MEDIA_DVD 0x0000 //source media is a DVD
#define SPDIF_MEDIA_CDVD 0x0200
#define SPDIF_MEDIA_400 0x0000
#define SPDIF_COPY_NORMAL 0x0000 // spdif stream is not protected
#define SPDIF_COPY_PROHIBIT 0x8000 // spdif stream can't be copied
/********************************************************************/
#define VOICE_PARAM_VOLL 0x0 // Voice Volume Left
#define VOICE_PARAM_VOLR 0x2 // Voice Volume Right
#define VOICE_PARAM_PITCH 0x4 // Pitch
#define VOICE_PARAM_ADSR1 0x6 // Envelope 1 (Attack-Delay-Sustain-Release)
#define VOICE_PARAM_ADSR2 0x8 // Envelope 2 (Attack-Delay-Sustain-Release)
#define VOICE_PARAM_ENVX 0xA // Current Envelope
#define VOICE_PARAM_VOLXL 0xC // Current Voice Volume Left
#define VOICE_PARAM_VOLXR 0xE // Current Voice Volume Right
/********************************************************************/
#define VOICE_ADDR_SSA 0x0 // Waveform data starting address
#define VOICE_ADDR_LSAX 0x4 // Loop point address
#define VOICE_ADDR_NAX 0x8 // Waveform data that should be read next
#endif // REGS_H_INCLUDED //

308
plugins/spu2ghz/regtable.h Normal file
View File

@ -0,0 +1,308 @@
//GiGaHeRz's SPU2 Driver
//Copyright (c) 2003-2008, David Quintana <gigaherz@gmail.com>
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#define U16P(x) ((u16*)&(x))
#define PCORE(c,p) \
U16P(Cores[c].##p)
#define PVCP(c,v,p) \
PCORE(c,Voices[v].##p)
#define PVC(c,v) \
PVCP(c,v,VolumeL.Reg_VOL), \
PVCP(c,v,VolumeR.Reg_VOL), \
PVCP(c,v,Pitch), \
PVCP(c,v,ADSR.Reg_ADSR1), \
PVCP(c,v,ADSR.Reg_ADSR2), \
PVCP(c,v,ADSR.Value)+1, \
PVCP(c,v,VolumeL.Value), \
PVCP(c,v,VolumeR.Value)
#define PVCA(c,v) \
PVCP(c,v,StartA)+1, \
PVCP(c,v,StartA), \
PVCP(c,v,LoopStartA)+1, \
PVCP(c,v,LoopStartA), \
PVCP(c,v,NextA)+1, \
PVCP(c,v,NextA)
#define PRAW(a) \
((u16*)NULL)
#define PREVB_REG(c,n) \
PCORE(c,Revb.##n)+1, \
PCORE(c,Revb.##n)
const u16 zero=0;
#pragma pack(push,1)
u16* /*const*/ regtable[] = {
// Voice Params: 8 params, 24 voices = 0x180 bytes
PVC(0, 0),PVC(0, 1),PVC(0, 2),PVC(0, 3),PVC(0, 4),PVC(0, 5),
PVC(0, 6),PVC(0, 7),PVC(0, 8),PVC(0, 9),PVC(0,10),PVC(0,11),
PVC(0,12),PVC(0,13),PVC(0,14),PVC(0,15),PVC(0,16),PVC(0,17),
PVC(0,18),PVC(0,19),PVC(0,20),PVC(0,21),PVC(0,22),PVC(0,23),
PCORE(0,Regs.PMON),
PCORE(0,Regs.PMON)+1,
PCORE(0,Regs.NON),
PCORE(0,Regs.NON)+1,
PCORE(0,Regs.VMIXL),
PCORE(0,Regs.VMIXL)+1,
PCORE(0,Regs.VMIXEL),
PCORE(0,Regs.VMIXEL)+1,
PCORE(0,Regs.VMIXR),
PCORE(0,Regs.VMIXR)+1,
PCORE(0,Regs.VMIXER),
PCORE(0,Regs.VMIXER)+1,
PCORE(0,Regs.MMIX),
PCORE(0,Regs.ATTR),
PCORE(0,IRQA)+1,
PCORE(0,IRQA),
U16P(zero),
U16P(zero),
U16P(zero),
U16P(zero),
PCORE(0,TSA)+1,
PCORE(0,TSA),
PRAW(0x1ac), PRAW(0x1ae),
PCORE(0,AutoDMACtrl),
PRAW(0x1b2), PRAW(0x1b4), PRAW(0x1b6), PRAW(0x1b8), PRAW(0x1ba), PRAW(0x1bc), PRAW(0x1be), // unknown
// Voice Addresses
PVCA(0, 0),PVCA(0, 1),PVCA(0, 2),PVCA(0, 3),PVCA(0, 4),PVCA(0, 5),
PVCA(0, 6),PVCA(0, 7),PVCA(0, 8),PVCA(0, 9),PVCA(0,10),PVCA(0,11),
PVCA(0,12),PVCA(0,13),PVCA(0,14),PVCA(0,15),PVCA(0,16),PVCA(0,17),
PVCA(0,18),PVCA(0,19),PVCA(0,20),PVCA(0,21),PVCA(0,22),PVCA(0,23),
PCORE(0,EffectsStartA)+1,
PCORE(0,EffectsStartA),
PREVB_REG(0,FB_SRC_A),
PREVB_REG(0,FB_SRC_B),
PREVB_REG(0,IIR_SRC_A0),
PREVB_REG(0,IIR_SRC_A1),
PREVB_REG(0,IIR_SRC_B1),
PREVB_REG(0,IIR_SRC_B0),
PREVB_REG(0,IIR_DEST_A0),
PREVB_REG(0,IIR_DEST_A1),
PREVB_REG(0,IIR_DEST_B0),
PREVB_REG(0,IIR_DEST_B1),
PREVB_REG(0,ACC_SRC_A0),
PREVB_REG(0,ACC_SRC_A1),
PREVB_REG(0,ACC_SRC_B0),
PREVB_REG(0,ACC_SRC_B1),
PREVB_REG(0,ACC_SRC_C0),
PREVB_REG(0,ACC_SRC_C1),
PREVB_REG(0,ACC_SRC_D0),
PREVB_REG(0,ACC_SRC_D1),
PREVB_REG(0,MIX_DEST_A0),
PREVB_REG(0,MIX_DEST_A1),
PREVB_REG(0,MIX_DEST_B0),
PREVB_REG(0,MIX_DEST_B1),
PCORE(0,EffectsEndA)+1,
U16P(zero),
PCORE(0,Regs.ENDX),
PCORE(0,Regs.ENDX)+1,
PCORE(0,Regs.STATX),
//0x346 here
PRAW(0x346),
PRAW(0x348),PRAW(0x34A),PRAW(0x34C),PRAW(0x34E),
PRAW(0x350),PRAW(0x352),PRAW(0x354),PRAW(0x356),
PRAW(0x358),PRAW(0x35A),PRAW(0x35C),PRAW(0x35E),
PRAW(0x360),PRAW(0x362),PRAW(0x364),PRAW(0x366),
PRAW(0x368),PRAW(0x36A),PRAW(0x36C),PRAW(0x36E),
PRAW(0x370),PRAW(0x372),PRAW(0x374),PRAW(0x376),
PRAW(0x378),PRAW(0x37A),PRAW(0x37C),PRAW(0x37E),
PRAW(0x380),PRAW(0x382),PRAW(0x384),PRAW(0x386),
PRAW(0x388),PRAW(0x38A),PRAW(0x38C),PRAW(0x38E),
PRAW(0x390),PRAW(0x392),PRAW(0x394),PRAW(0x396),
PRAW(0x398),PRAW(0x39A),PRAW(0x39C),PRAW(0x39E),
PRAW(0x3A0),PRAW(0x3A2),PRAW(0x3A4),PRAW(0x3A6),
PRAW(0x3A8),PRAW(0x3AA),PRAW(0x3AC),PRAW(0x3AE),
PRAW(0x3B0),PRAW(0x3B2),PRAW(0x3B4),PRAW(0x3B6),
PRAW(0x3B8),PRAW(0x3BA),PRAW(0x3BC),PRAW(0x3BE),
PRAW(0x3C0),PRAW(0x3C2),PRAW(0x3C4),PRAW(0x3C6),
PRAW(0x3C8),PRAW(0x3CA),PRAW(0x3CC),PRAW(0x3CE),
PRAW(0x3D0),PRAW(0x3D2),PRAW(0x3D4),PRAW(0x3D6),
PRAW(0x3D8),PRAW(0x3DA),PRAW(0x3DC),PRAW(0x3DE),
PRAW(0x3E0),PRAW(0x3E2),PRAW(0x3E4),PRAW(0x3E6),
PRAW(0x3E8),PRAW(0x3EA),PRAW(0x3EC),PRAW(0x3EE),
PRAW(0x3F0),PRAW(0x3F2),PRAW(0x3F4),PRAW(0x3F6),
PRAW(0x3F8),PRAW(0x3FA),PRAW(0x3FC),PRAW(0x3FE),
//AND... we reached 0x400!
// Voice Params: 8 params, 24 voices = 0x180 bytes
PVC(1, 0),PVC(1, 1),PVC(1, 2),PVC(1, 3),PVC(1, 4),PVC(1, 5),
PVC(1, 6),PVC(1, 7),PVC(1, 8),PVC(1, 9),PVC(1,10),PVC(1,11),
PVC(1,12),PVC(1,13),PVC(1,14),PVC(1,15),PVC(1,16),PVC(1,17),
PVC(1,18),PVC(1,19),PVC(1,20),PVC(1,21),PVC(1,22),PVC(1,23),
PCORE(1,Regs.PMON),
PCORE(1,Regs.PMON)+1,
PCORE(1,Regs.NON),
PCORE(1,Regs.NON)+1,
PCORE(1,Regs.VMIXL),
PCORE(1,Regs.VMIXL)+1,
PCORE(1,Regs.VMIXEL),
PCORE(1,Regs.VMIXEL)+1,
PCORE(1,Regs.VMIXR),
PCORE(1,Regs.VMIXR)+1,
PCORE(1,Regs.VMIXER),
PCORE(1,Regs.VMIXER)+1,
PCORE(1,Regs.MMIX),
PCORE(1,Regs.ATTR),
PCORE(1,IRQA)+1,
PCORE(1,IRQA),
U16P(zero),
U16P(zero),
U16P(zero),
U16P(zero),
PCORE(1,TSA)+1,
PCORE(1,TSA),
PRAW(0x5ac), PRAW(0x5ae),
PCORE(1,AutoDMACtrl),
PRAW(0x5b2), PRAW(0x5b4), PRAW(0x5b6), PRAW(0x5b8), PRAW(0x5ba), PRAW(0x5bc), PRAW(0x5be), // unknown
// Voice Addresses
PVCA(1, 0),PVCA(1, 1),PVCA(1, 2),PVCA(1, 3),PVCA(1, 4),PVCA(1, 5),
PVCA(1, 6),PVCA(1, 7),PVCA(1, 8),PVCA(1, 9),PVCA(1,10),PVCA(1,11),
PVCA(1,12),PVCA(1,13),PVCA(1,14),PVCA(1,15),PVCA(1,16),PVCA(1,17),
PVCA(1,18),PVCA(1,19),PVCA(1,20),PVCA(1,21),PVCA(1,22),PVCA(1,23),
PCORE(1,EffectsStartA)+1,
PCORE(1,EffectsStartA),
PREVB_REG(1,FB_SRC_A),
PREVB_REG(1,FB_SRC_B),
PREVB_REG(1,IIR_SRC_A0),
PREVB_REG(1,IIR_SRC_A1),
PREVB_REG(1,IIR_SRC_B1),
PREVB_REG(1,IIR_SRC_B0),
PREVB_REG(1,IIR_DEST_A0),
PREVB_REG(1,IIR_DEST_A1),
PREVB_REG(1,IIR_DEST_B0),
PREVB_REG(1,IIR_DEST_B1),
PREVB_REG(1,ACC_SRC_A0),
PREVB_REG(1,ACC_SRC_A1),
PREVB_REG(1,ACC_SRC_B0),
PREVB_REG(1,ACC_SRC_B1),
PREVB_REG(1,ACC_SRC_C0),
PREVB_REG(1,ACC_SRC_C1),
PREVB_REG(1,ACC_SRC_D0),
PREVB_REG(1,ACC_SRC_D1),
PREVB_REG(1,MIX_DEST_A0),
PREVB_REG(1,MIX_DEST_A1),
PREVB_REG(1,MIX_DEST_B0),
PREVB_REG(1,MIX_DEST_B1),
PCORE(1,EffectsEndA)+1,
U16P(zero),
PCORE(1,Regs.ENDX),
PCORE(1,Regs.ENDX)+1,
PCORE(1,Regs.STATX),
PRAW(0x746),
PRAW(0x748),PRAW(0x74A),PRAW(0x74C),PRAW(0x74E),
PRAW(0x750),PRAW(0x752),PRAW(0x754),PRAW(0x756),
PRAW(0x758),PRAW(0x75A),PRAW(0x75C),PRAW(0x75E),
//0x760: weird area
PCORE(0,MasterL.Reg_VOL),
PCORE(0,MasterR.Reg_VOL),
PCORE(0,FxL),
PCORE(0,FxR),
PCORE(0,ExtL),
PCORE(0,ExtR),
PCORE(0,InpL),
PCORE(0,InpR),
PCORE(0,MasterL.Value),
PCORE(0,MasterR.Value),
PCORE(0,Revb.IIR_ALPHA),
PCORE(0,Revb.ACC_COEF_A),
PCORE(0,Revb.ACC_COEF_B),
PCORE(0,Revb.ACC_COEF_C),
PCORE(0,Revb.ACC_COEF_D),
PCORE(0,Revb.IIR_COEF),
PCORE(0,Revb.FB_ALPHA),
PCORE(0,Revb.FB_X),
PCORE(0,Revb.IN_COEF_L),
PCORE(0,Revb.IN_COEF_R),
PCORE(1,MasterL.Reg_VOL),
PCORE(1,MasterR.Reg_VOL),
PCORE(1,FxL),
PCORE(1,FxR),
PCORE(1,ExtL),
PCORE(1,ExtR),
PCORE(1,InpL),
PCORE(1,InpR),
PCORE(1,MasterL.Value),
PCORE(1,MasterR.Value),
PCORE(1,Revb.IIR_ALPHA),
PCORE(1,Revb.ACC_COEF_A),
PCORE(1,Revb.ACC_COEF_B),
PCORE(1,Revb.ACC_COEF_C),
PCORE(1,Revb.ACC_COEF_D),
PCORE(1,Revb.IIR_COEF),
PCORE(1,Revb.FB_ALPHA),
PCORE(1,Revb.FB_X),
PCORE(1,Revb.IN_COEF_L),
PCORE(1,Revb.IN_COEF_R),
PRAW(0x7B0),PRAW(0x7B2),PRAW(0x7B4),PRAW(0x7B6),
PRAW(0x7B8),PRAW(0x7BA),PRAW(0x7BC),PRAW(0x7BE),
// SPDIF interface
U16P(Spdif.Out),
U16P(Spdif.Info),
U16P(Spdif.Unknown1),
U16P(Spdif.Mode),
U16P(Spdif.Media),
U16P(Spdif.Unknown2),
U16P(Spdif.Protection),
PRAW(0x7CE),
PRAW(0x7D0),PRAW(0x7D2),PRAW(0x7D4),PRAW(0x7D6),
PRAW(0x7D8),PRAW(0x7DA),PRAW(0x7DC),PRAW(0x7DE),
PRAW(0x7E0),PRAW(0x7E2),PRAW(0x7E4),PRAW(0x7E6),
PRAW(0x7E8),PRAW(0x7EA),PRAW(0x7EC),PRAW(0x7EE),
PRAW(0x7F0),PRAW(0x7F2),PRAW(0x7F4),PRAW(0x7F6),
PRAW(0x7F8),PRAW(0x7FA),PRAW(0x7FC),PRAW(0x7FE),
U16P(zero)
};

Some files were not shown because too many files have changed in this diff Show More