mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
09cf85f57d
commit
14d14ec6b9
|
@ -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.
|
|
@ -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!
|
||||||
|
|
|
@ -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
|
||||||
|
//
|
|
@ -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__ */
|
|
@ -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__ */
|
Binary file not shown.
|
@ -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
|
|
@ -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
|
|
@ -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>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
@ -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
|
@ -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
|
|
@ -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>
|
|
@ -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
|
@ -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
|
|
@ -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();
|
||||||
|
}
|
|
@ -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
|
|
@ -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_
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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=
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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_
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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:
|
||||||
|
-------------------
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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__ */
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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__
|
|
@ -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;
|
||||||
|
};
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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__
|
||||||
|
|
|
@ -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;
|
|
@ -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();
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
||||||
|
}
|
|
@ -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 //
|
|
@ -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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 //
|
|
@ -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)
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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 //
|
|
@ -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;
|
|
@ -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;
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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);
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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 */
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
||||||
|
};
|
|
@ -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 */
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
File diff suppressed because it is too large
Load Diff
|
@ -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 //
|
|
@ -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
|
|
@ -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 //
|
|
@ -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
Loading…
Reference in New Issue