Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ef91ce464c | |||
| 0ba54f14d3 | |||
| 0a330b490f | |||
| 65e0083de0 | |||
| 6237b9f50e | |||
| ba04dbb4ef | |||
| 2fffad141d | |||
| 44182cc6eb | |||
| 72bb48afdd | |||
| ecbaa4142b | |||
| e69312eabd | |||
| b5a97f1d55 | |||
| 00e8ac983c | |||
| be62b682da | |||
| 8868472869 | |||
| beba11c372 | |||
| 5c1a41ec41 | |||
| 01f163576d | |||
| be0e841c42 | |||
| 40e9ff65bb | |||
| c4bd988726 | |||
| 17ccc013a8 | |||
| bb866b0f91 | |||
| ac3ceae429 | |||
| 69a6fe7856 | |||
| 5fd058a7ea | |||
| f463dc6b7a | |||
| d8d6f0d807 | |||
| 08f893779e | |||
| 23b9a5de5a | |||
| e5b42325c9 | |||
| fb4cc1323e | |||
| 8e6c44a63e | |||
| 052a4b7020 | |||
| fd5294ab09 | |||
| 3ee18feec9 | |||
| a69f54e944 | |||
| c1823b4021 | |||
| 27b26480c6 | |||
| fd071b24b5 | |||
| 34bc63a962 | |||
| 41e7cbb149 | |||
| 4cc81aa4ac | |||
| eac78b39e1 | |||
| 8245238796 | |||
| d16ec11885 | |||
| 3d80d60170 | |||
| 4674e6e71d | |||
| 4269e63ba9 | |||
| 9596973f2b | |||
| 817ae4c84b | |||
| ada23edf7f | |||
| f5ba2b307d | |||
| f11164a1f4 | |||
| 0f1f2580f1 | |||
| 4ab0b010b2 | |||
| 6790464f1c | |||
| f4bb22c7b0 | |||
| 344384e397 | |||
| 55778fe610 | |||
| 64da32c6d6 | |||
| ffbd062550 | |||
| 7ddebab56a | |||
| 272a093957 | |||
| ac7031c753 | |||
| 2c314f92ee | |||
| 9fbc420dfb |
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. 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 program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
@@ -0,0 +1,551 @@
|
||||
Version 0.5.1
|
||||
-------------
|
||||
- Build improvements
|
||||
- Increase standards compliance and code quality
|
||||
- Add the SoX Resampler for higher quality (but higher CPU usage) resampling
|
||||
- Add SameBoy's "Modern - Accurate" colour correction
|
||||
|
||||
Version 0.5.0
|
||||
-------------
|
||||
- Initial tagged release after fork from final public revision of Gambatte
|
||||
- Stricter build flags
|
||||
- Removal of stale, bitrotten code
|
||||
- Rearrange and simplify codebase layout
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- 0.4.1 -- 2009-01-10
|
||||
libgambatte:
|
||||
- Fix HqXx filter pitch.
|
||||
- Fix mbc2 not getting a rambank.
|
||||
- Make sure to reset passed pointers when deleted. Fixes potential crash
|
||||
when loading ROM during OAM busy.
|
||||
common:
|
||||
- Substantially improved rate estimation averaging.
|
||||
- RateEst: Add a convenient way of filtering measures that extend beyond
|
||||
a buffer time, and are as such probably invalid.
|
||||
- RateEst: Allow using a custom timestamp in feed().
|
||||
- RateEst: Keep a queue of the last ~100 msec worth of samples and
|
||||
duration, and filter out collective samples that give a pre-estimate
|
||||
that seems way off.
|
||||
- Replace "Game Boy / Game Boy Color emulator" with "Game Boy Color
|
||||
emulator" for now to avoid misleading anyone on the current status.
|
||||
gambatte_qt:
|
||||
- Disable BlitterWidget updates (paintEvents) while not paused.
|
||||
- QGLBlitter: Do a cheap front blit rather than a vsynced flip if audio
|
||||
buffers are low.
|
||||
- Allow BlitterWidgets to opt in to get paintEvents while unpaused. Do so
|
||||
for QGLBlitter since it may need to clear buffers afterwards.
|
||||
- QGLBlitter: Try to blit right after sync in the case of single buffering.
|
||||
- Up default audio buffer latency to 100 ms (some common system audio
|
||||
servers require a lot of buffering to work well).
|
||||
- Adaptively skip BlitterWidget syncs if audio buffer is low, in a manner
|
||||
that should minimize wasted skips in sync to vblank situation, and tries
|
||||
to be non-disturbing. This replaces frame time halving, and blitter
|
||||
specific rescueing.
|
||||
- Clear display buffers in DirectDrawBlitter and Direct3DBlitter in
|
||||
exclusive mode, since blits don't necessarily cover the entire buffers.
|
||||
- DirectDrawBlitter: Make sure that a minimum amount of time has passed
|
||||
between calls to WaitForVerticalBlank, since it can return in the same
|
||||
vblank period twice on a fast system.
|
||||
- DirectDrawBlitter: Support vsync for refresh rate ~= 2x frame rate.
|
||||
- DirectDrawBlitter: Refactor somewhat and get rid of a couple minor
|
||||
potential bugs.
|
||||
- DirectDrawBlitter: Some tweaks to get updates closer to sync time in
|
||||
certain situations.
|
||||
- DirectDrawBlitter: Some tweaks to better support DONOTWAIT.
|
||||
- DirectDrawBlitter: Make only updating during vblank while page flipping
|
||||
optional.
|
||||
- Direct3DBlitter: Some tweaks to get updates closer to sync time in
|
||||
certain situations.
|
||||
- Filter out very short frame times in frame time estimation.
|
||||
- Don't adjust frame time during turbo, but rather skip BlitterWidget
|
||||
syncs to speed up, which avoids vsync limits without disabling vsync.
|
||||
- DirectDrawBlitter: Add triple buffering option.
|
||||
- Direct3DBlitter: Use D3DSWAPEFFECT_DISCARD in non-exclusive mode.
|
||||
- Direct3DBlitter: Allow triple buffering and vblank-only updates in
|
||||
non-excusive mode.
|
||||
- Rename "Page flipping" in Direct3D and DirectDraw blitters to
|
||||
"Exclusive full screen".
|
||||
- Pause audio on win32 titlebar clicks/drags to avoid looping audio due to
|
||||
underruns from blocked timerEvents.
|
||||
- Use wildcards for platform detection to avoid being unnecessarily
|
||||
compiler/architecture specific. Fixes bug 2377772.
|
||||
- Rewrite most of DirectSoundEngine, supporting primary buffer option,
|
||||
making it more robust, correct and hopefully cleaner. Only use part of
|
||||
the primary buffer if the desired buffer size is lower than the
|
||||
primary buffer size.
|
||||
- Direct3DBlitter and DirectDrawBlitter: Force blocking updates when sync
|
||||
to vblank is enabled. Some updates only block if there's a prior
|
||||
unfinished update in progress. This screws up frame time estimation in
|
||||
turn screwing up vsync. To fix this we do a double update (and extra blit)
|
||||
if close to a frame time period has passed since the last update when
|
||||
sync to vblank is enabled. I really should have noticed this earlier as
|
||||
it pretty much breaks vsync adaption completely.
|
||||
- Direct3DBlitter: Use the D3DCREATE_FPU_PRESERVE flag when creating
|
||||
device. Omitting this flag can screw up floating point calculations in
|
||||
other parts of the code. For instance WASAPI cursor timestamps get
|
||||
utterly screwed up here.
|
||||
- Direct3DBlitter: It appears that managed textures are updated before
|
||||
they are unlocked, which screws up redraws, making things appear choppy
|
||||
in some situations. Use a default memory texture and a system memory
|
||||
texture and the UpdateTexure method instead.
|
||||
- DirectSoundEngine: Make use of the sample period limit feature of
|
||||
RateEst, rather than duplicating the feature.
|
||||
- Add polling WASAPI engine with exclusive mode support. Latency and rate
|
||||
estimation is generally better than DirectSound, and in exclusive mode
|
||||
there is less blocking as well as exclusive mode being better than
|
||||
shared mode in the other areas too.
|
||||
- WasapiEngine: Add device selection.
|
||||
- WasapiEngine: Add static isUsable() method. Only listed if isUsable().
|
||||
Default engine if isUsable().
|
||||
- WasapiEngine: Use default device if there's only one device available,
|
||||
since we don't show the combobox anyway.
|
||||
- DirectSoundEngine: Provide the integrated read and status get write
|
||||
method optimization.
|
||||
- XvBlitter: Set NosystemBackground attribute rather than OpaquePaintEvent.
|
||||
Reimplement paintEngine to return NULL as suggested by Qt docs.
|
||||
- X11Blitter: Reimplement paintEngine to return NULL.
|
||||
- AlsaEngine: Make use of sample period limit feature of RateEst. Don't
|
||||
increase estimated sample rate on underrun.
|
||||
- OssEngine: Make use of sample period limit feature of RateEst. Don't
|
||||
increase estimated sample rate on underrun.
|
||||
- Esc exits fullscreen on macx.
|
||||
- Drop OpenAL from default macx binary.
|
||||
- Add some useful but commented build flags for macx to .pro files.
|
||||
|
||||
-- 0.4.0 -- 2008-10-27
|
||||
libgambatte:
|
||||
- less fixed-width type dependencies. don't assume unsigned int > 16 bits
|
||||
- slightly faster sprite mapping
|
||||
- Skip potential high frequency events when they don't matter.
|
||||
- do sprite sorting and cycle calculations pr line as needed instead of all
|
||||
at once
|
||||
- fix broken volume on/off event notification
|
||||
- less int > 16-bits assumptions
|
||||
- more type width dependency fixes
|
||||
- int width deps. Gambatte namespace
|
||||
- wx affects sprite m3 cycles
|
||||
- cache m3 cycles, related refactoring
|
||||
- readjust cgb dma cycles to previously changed m3 timing
|
||||
- clean up goofy lyc calculation.
|
||||
- cgb dma from various areas results in 0xFF being written.
|
||||
- 0xFEA0-0xFEFF not writable when OAM isn't
|
||||
- unusable ioram bits fixes
|
||||
- dmg ioram startup state fixes.
|
||||
- various oamdma accuracy
|
||||
- oamdma bus conflicts with cpu, ppu, cgbdma.
|
||||
- rewritten memory read/write methods.
|
||||
- accurate timing of ppu sprite mapping reads.
|
||||
- fix recent cgb sprite cycles sorting slip up.
|
||||
- preoffset mem pointers.
|
||||
- get rid of unused memory.
|
||||
- save state infrastructure,
|
||||
- clean up video timing code,
|
||||
- use save state for initialization and reset,
|
||||
- do color conversion outside filters
|
||||
- fast rgb32ToUyvy,
|
||||
- add overlooked oamdma event,
|
||||
- adjust subcycle irq timing (shouldn't affect anything),
|
||||
- various refactoring
|
||||
- save savedata before loading state
|
||||
- fix silly initstate ifreg regression
|
||||
- save state selection
|
||||
- save state osd preview snapshots
|
||||
- fix a few potential security holes when loading invalid state
|
||||
- get rid of some undefined behaviour in statesaver
|
||||
- always draw in rgb32, color convert afterwards, too bad for maemo/16-bit
|
||||
depth users
|
||||
- get rid of silly c string stuff
|
||||
- add bitmap font rendering with font based on Bitstream Vera Sans
|
||||
- osd state n saved/loaded text
|
||||
- empty state osd thumbs marked with "Empty" text
|
||||
- adjust thumbnail interpolation weighing slightly
|
||||
- utilize templates for more flexible osd text printing
|
||||
- use grey osd text with black outline for save/load state messages
|
||||
- move state 0 OSD pos to rightmost to match kbd layout
|
||||
- state 1 default on ROM load
|
||||
- support external save state files
|
||||
- missing includes
|
||||
- missing virtual destructor
|
||||
- std::ifstream construction missing binary flag
|
||||
- fix gcc-4.3 compilation
|
||||
- avoid signed overflow in constant (which is both undefined and likely
|
||||
to cause problems on architectures where sizeof(long) != sizeof(int)) in
|
||||
rgb2yuv code.
|
||||
- Fix wrong pitch passed to filter if color conversion is needed.
|
||||
- Fix potential problem with rgb32ToUyvy cache init values on 16-bit systems
|
||||
- Correct unhalttime when resetting counters. Fixes perodic infinite halt
|
||||
issue in Kirby's Star Stacker and probably other games.
|
||||
- Fix LY display disable regression
|
||||
- Use deltas and a running sum to decrease buffer writes in sound emulation
|
||||
sample generation.
|
||||
- Rearrange sound emulation event loop to optimize for high-frequency event
|
||||
units.
|
||||
- Initialize palette arrays to avoid valgrind noise.
|
||||
- Don't do resampling in libgambatte. Update API to reflect this.
|
||||
- No rambanks for ROMs that don't request any.
|
||||
- Route invalid rombank addresses in non-power-of-2 number of rombanks
|
||||
cases to disabled area assuming ceiled power of 2 address bus.
|
||||
- no sprites or sprite mapping busy cycles on first line after display
|
||||
enable. slight cleanup.
|
||||
- small oam accessibility correction.
|
||||
- Tile loading and tile rendering can seemingly get out of sync when
|
||||
modifying scx at a critical time. Another pessimation with little gain in
|
||||
the name of accuracy.
|
||||
- Use a look-up table to do tile byte merging.
|
||||
- Append "_dmg" to save base name when forcing DMG mode, to avoid
|
||||
corrupting CGB save files and vice versa.
|
||||
- saner ly write behaviour
|
||||
- Add adapted and optimized hq3x.
|
||||
- Revert to big f'ing switch hq2x code, as there's less duplication now.
|
||||
Also optimized interpolation functions further. No idea how I missed that
|
||||
initially.
|
||||
- Lower opacity OSD text.
|
||||
gambatte_sdl:
|
||||
- less retarded indenting
|
||||
- saner placement of fill_buffer function
|
||||
- int width deps. Gambatte namespace
|
||||
- Scalebuffer dstpitch aware.
|
||||
- save state selection
|
||||
- add number key slot selection shortcuts
|
||||
- Estimate actual output sample rate in terms of OS timers
|
||||
and derive frame rate from it.
|
||||
- Move AudioData and RingBuffer classes to separate files.
|
||||
- Make underruns slightly less painful, by resetting buffer
|
||||
positions.
|
||||
- Skip resampling when fast-forwarding
|
||||
- Fill available buffer space before waiting for more.
|
||||
- Audio buffer command line options.
|
||||
- Use half video frame sleep time if audio buffer is close to underrun.
|
||||
- Adjust estimated frame time each frame.
|
||||
gambatte_qt:
|
||||
- more likely to build on mac os x
|
||||
- Fix fixed window size issues with various window managers (metacity,
|
||||
xfwm4...)
|
||||
- macx build fixes
|
||||
- hopefully fix opengl clearing issues
|
||||
- Gambatte namespace
|
||||
- Decouple Qt GUI from gambatte.
|
||||
- Lots of cleanups, flexibility added
|
||||
- setting of various properties, frame time, aspect ratio, button events,
|
||||
video sources, sample rates, pauseOnDialogExec, custom menus etc.
|
||||
- Document some interfaces.
|
||||
- Support for setting approximate sound buffer latency.
|
||||
- Use rational math for 100% exact timers (even though the actual system
|
||||
timers are unlikely to be accurate).
|
||||
- Add fast-forward to input settings.
|
||||
- timeGetTime() fallback for win32
|
||||
- Store full screen mode values/text rather than less reliable indexes.
|
||||
- Repaint on xvblitter port changes to avoid color key not getting
|
||||
repainted.
|
||||
- improved ALSA buffer reporting
|
||||
- add sampleRate info to MediaSource::setSampleBuffer.
|
||||
- clarify that "samples" refers to stereo samples
|
||||
- fix 24-bit depth non-shm ximage creation
|
||||
- fix blittercontainer incorrectly using minimumSize for integer scaling
|
||||
- add unrestricted fast bilinear and nearest neighbor sw scaling to
|
||||
x11/qpainter blitter
|
||||
- swscale: remove forgotten static qualifiers
|
||||
- swscale: center linear weighing bias
|
||||
- swscale: exclude iostream
|
||||
- swscale: less bloated
|
||||
- macx fixed/variable window size change issue fixed
|
||||
- macx opengl drawbuffer change issues worked around
|
||||
- add openal engine, default on macx
|
||||
- add macx quartz video mode toggler
|
||||
- multi-head infrastructure
|
||||
- support multiple monitors in macx quartz toggler
|
||||
- more work-arounds for Qt failing to set correct geometry on video mode
|
||||
changes.
|
||||
- more explicit fast-forward button handling, to avoid missed key
|
||||
press/release events on macx
|
||||
- opengl doublebuffer preblitting, try to make actual screen updates as
|
||||
close to right after sync wait is over as possible
|
||||
- add xf86vidmode toggler (xrandrtoggler is default)
|
||||
- x11blitter: check for other supported visuals if the default is
|
||||
unsupported.
|
||||
- temporarily return to original video mode and minimize on full screen
|
||||
alt-tab (except on macx or if there are multiple screens), switch back on
|
||||
focus-in
|
||||
- hide mouse cursor after move timeout, or key/joystick pressed (more sane
|
||||
on macx)
|
||||
- exit fullscreen rather than toggle menubar on macx (note that the menubar
|
||||
will automatically pop-up on macx full screen if the mouse is moved to
|
||||
the top of the primary screen)
|
||||
- add (independent) pause counter for non-client pauses.
|
||||
- reset X11 screen saver on joystick activity
|
||||
- change "turbo"-mode to temporarily set frametime as a way of avoiding
|
||||
vsync issues (for a laugh, check out the video dialog while in
|
||||
fast-forward mode and see "Sync to vertical blank in 65535 and 131070 Hz
|
||||
modes").
|
||||
- fix win32 compilation
|
||||
- refix win32 fullscreen geometry correction
|
||||
- neater win32 BlitterWidget::sync
|
||||
- avoid misleading minimize on fullscreen close
|
||||
- refactor Blitterwidget::sync
|
||||
- directdrawblitter: remove unecessary turbo conditions
|
||||
- gditoggler: add multi-monitor support (win32)
|
||||
- videodialog: save actual hz values for real this time
|
||||
- quartztoggler: avoid potentially reverting to the wrong mode on double
|
||||
setFullMode(false) in multi-head configs
|
||||
- make sure window is within screen after mode change, so Qt doesn't reset
|
||||
it to the primary screen
|
||||
- revert to previous win32 fullscreen geometry correction behaviour so that
|
||||
the geometry gets properly reset after fullscreen
|
||||
- Add directdraw device selection.
|
||||
- directsoundengine: add device selection.
|
||||
- directdrawblitter: only list devices if there are more than 2 devices
|
||||
(including primary)
|
||||
- directdrawblitter: use private static member rather than global friend
|
||||
enumeration callback
|
||||
- capitalization changes
|
||||
- add direct3d9 blitter with support for vsync, bf, page flipping, triple
|
||||
buffering, device selection, multi-head etc. d3d9.dll loaded at runtime
|
||||
- more strict and thorough exclusive mode handling to support d3d fullscreen
|
||||
- work around file open dialog not returning focus properly
|
||||
- gditoggler: use current registry settings for return modes
|
||||
- directsoundengine: set DSBCAPS_GETCURRENTPOSITION2 flag
|
||||
- revert bad macx return from fullscreen on menu-toggle
|
||||
- don't build xf86vidmodetoggler by default
|
||||
- add save state actions to GUI menu
|
||||
- clean up GUI menu creation code
|
||||
- move GUI recent files to submenu
|
||||
- support external save state files
|
||||
- add number key slot selection shortcuts
|
||||
- missing includes
|
||||
- missing virtual destructor
|
||||
- make sure windows path arguments don't use backslashes by using QFileInfo
|
||||
- add Play menu with Pause, Frame Step, Dec/Inc/Reset Frame Rate
|
||||
- Add tab support to input settings dialog.
|
||||
- Add alternate key support to input settings dialog.
|
||||
- Auto-focus to next likely input box after settings key in input dialog.
|
||||
- Add "Play" and "State" input settings dialog tabs.
|
||||
- Avoid using the most convenient keys as forced menu short-cuts, set them
|
||||
as default keys in input settings dialog instead. This unfortunately
|
||||
makes the more useful shortcuts less visible, but it allows remapping
|
||||
the most convenient keyboard keys.
|
||||
- Avoid duplicate joystick axis "press" events by keeping a map of axis
|
||||
states.
|
||||
- Make sure to discard irrelevant/old joystick events.
|
||||
- Don't give MediaSource button events when stopped.
|
||||
- Allow joystick-based button events while paused by using a very
|
||||
low-frequency poll timer.
|
||||
- Make some of the joystick event wrapping stuff less messy.
|
||||
- missing string include
|
||||
- use QString for videoSourceLabel passed to MainWindow constructor
|
||||
- store currently selected scheme as string, since it appears ModelIndex
|
||||
is neither tied to the data it points to nor invalidated by changes.
|
||||
enforce valid state on reject since the list of schemes may have
|
||||
changed.
|
||||
- Direct3DCreate function pointer typedef needs WINAPI macro
|
||||
- disable page flipping dependent checkboxes in constructor to ensure
|
||||
correct start state
|
||||
- add custom sample rate support
|
||||
- change default buffer latency to 67 ms
|
||||
- don't auto-repeat buttons bound to keyboard
|
||||
- use enums for somewhat more robust gambattesource button setup
|
||||
- fix silly "alsa not using default device by default" bug
|
||||
- Only ask for xrandr config once to avoid potential server roundtrips in
|
||||
some xrandr versions.
|
||||
- Make sure xrandr version is >= 1.1 and < 2
|
||||
- Prevent all text editing of input boxes.
|
||||
- Add custom context menu to input boxes.
|
||||
- Update AudioEngine to support sample rate estimation in terms of OS
|
||||
timers.
|
||||
- Implement sample rate estimation in ALSA and OSS audio engines.
|
||||
- AlsaEngine: Revert to using snd_pcm_avail_update for buffer status since
|
||||
snd_pcm_delay may consider external latencies.
|
||||
- AlsaEngine: Use snd_pcm_hw_params_set_buffer_time_near. Don't request a
|
||||
particular number of periods per buffer.
|
||||
- AlsaEngine: Use hw as default custom device string, rather than hw:0,0.
|
||||
- OssEngine: Don't trust GETOSPACE fragment info.
|
||||
- Estimate optimal frame rate based on sample rate estimations.
|
||||
- Extend BlitterWidget to support estimation of vsynced frame rate in terms
|
||||
of OS timers.
|
||||
- Implement vsync frame rate estimation in QGlBlitter, Direct3DBlitter and
|
||||
DirectDrawBlitter.
|
||||
- Use a combination of OS timer sample rate estimation and vsync frame rate
|
||||
estimation to derive resampling ratio for no-frame-duplication vsync.
|
||||
- Change API to reflect MediaSources not being responsible for resampling.
|
||||
- Make sure to parent PaletteDialog list model, so it gets deleted properly.
|
||||
- Various refactoring, small changes and stuff I forgot.
|
||||
- limit vsync frame rate estimation deviation
|
||||
- More averaging in estimation code.
|
||||
- Stricter estimate deviation limit
|
||||
- Adjust estimated frame time each frame.
|
||||
- Use half frame time if audio buffer is close to underrun.
|
||||
- Provide combined audioengine write and status get, to avoid doing
|
||||
potentially expensive operations twice. Utilized in OSS and ALSA engines.
|
||||
- Saner vsync estimate variance protection.
|
||||
- allow dynamically setting samples per frame
|
||||
- Don't bother allowing sources the choice of which output sample rates are
|
||||
selecrable, as it's not really a per source thing at this point. If
|
||||
resampling avoidance is desired, then that should rather be a user option
|
||||
(to depend on the OS for resampling, which is mostly nonsensical for the
|
||||
Game Boy/NES/PSG-system case btw).
|
||||
- Move Qt media framework to a separate subdir
|
||||
- postpone buffered x11 blits to after sync.
|
||||
- Add support for XRandR 1.2 + multi-head
|
||||
- use crtc mode dimensions rather than crtc dimensions when discarding
|
||||
modes since crtc dimensions may be rotated
|
||||
- Fractional bits for intermediate rate estimation averages.
|
||||
- Add RateEst reset method. Initialize RateEst count to 1.
|
||||
- Less refresh rate estimation averaging.
|
||||
- Allow more refresh rate estimation deviation.
|
||||
- Return NULL paintEngine in windows blitters that use the PaintToScreen
|
||||
attribute.
|
||||
- Add checks for things not being initialized in DirectDraw-blitter and
|
||||
QPainterBlitter paintEvents.
|
||||
- Don't reparent blitters (mainly to make a bug in Qt 4.4.3 win less
|
||||
annoying, widgets that do internal reparenting are still affected).
|
||||
- Check for window position less than screen top-left after mode change,
|
||||
before full screen, to avoid Qt moving it to the primary screen.
|
||||
- Add rate estimation to DirectSound engine.
|
||||
- Better underrun detection in DirectSound engine.
|
||||
- Don't duplicate blitter pointer in mainwindow.
|
||||
- Use RateEst.reset rather than re-initing on pause.
|
||||
- Add CoreAudio engine with rate estimation and buffer status support.
|
||||
Default engine on Mac OS X.
|
||||
- 44100 Hz default sample rate on OS X, since OS X tends to resample
|
||||
everything to 44100 Hz.
|
||||
- Get rid of buffer status averaging in OpenAlEngine, since it makes
|
||||
assumptions on usage pattern that shouldn't be made.
|
||||
- Fix CoreAudio engine reporting buffer status in samples rather than
|
||||
frames.
|
||||
- Update SDL_Joystick to SDL-1.2 SVN.
|
||||
- #undef UNICODE in win32/SDL_mmjoystick.c to avoid joystick name mangling.
|
||||
- work around annoying random non-updating OpenGL on Mac OS X after full
|
||||
screen.
|
||||
common/other:
|
||||
- Fix GCC 4.3 warnings about people getting confused by operator precedence
|
||||
by adding parentheses.
|
||||
- Real-time, sophisticated resampling framework with several
|
||||
performance/quality profiles for dynamically generated windowed sinc and
|
||||
CIC chains based on analysis of fourier transforms and optimal cost
|
||||
equations. Fast 2-tap linear as a low quality alternative.
|
||||
- Move non-emulation common code to a common directory to avoid duplication.
|
||||
- Update front-ends to new libgambatte API.
|
||||
- Utilize resampling framework in front-ends. Selectable resamplers.
|
||||
- Improved adaptive sleep class that estimates oversleep.
|
||||
- Various refactoring, small changes and stuff I forgot.
|
||||
- Do per phase normalization to avoid dc fluctuations.
|
||||
- More averaging in estimation code.
|
||||
- Stricter estimate deviation limit
|
||||
- Fractional bits for intermediate rate estimation averages.
|
||||
- Add RateEst reset method. Initialize RateEst count to 1.
|
||||
- Extend ringbuffer.h to support resetting size, and move it to common dir
|
||||
since gambatte_qt/coreaudioengine uses it too now.
|
||||
- Add "force DMG mode" option.
|
||||
- Allow more rate estimation deviation.
|
||||
hwtests:
|
||||
- wx affects sprite m3 cycles.
|
||||
- cgb dma from various areas results in 0xFF being written.
|
||||
- add hwtests for oam dma
|
||||
- m3 cycles wo bg
|
||||
- more oamdma tests
|
||||
- various oamdma accuracy. oamdma bus conflicts with cpu, ppu, cgbdma.
|
||||
- accurate timing of ppu sprite mapping reads.
|
||||
|
||||
-- 0.3.1 -- 2007-10-26 --
|
||||
gambatte_qt:
|
||||
- Enable Joystick POV-Hat events.
|
||||
|
||||
-- 0.3.0 -- 2007-10-26 --
|
||||
libgambatte:
|
||||
- Fix adc/sbc and add_hl_rr hfc calc, sp_plus_n cf/hcf calc and daa thanks
|
||||
to blargg.
|
||||
- document HF2 better
|
||||
- Update sound core according to blargg's findings.
|
||||
- Improve resampling quality and performance.
|
||||
- Fix overlooked "add hl,sp" flag calculation.
|
||||
- fix initial endtime value
|
||||
- check for resampling ratio < 1
|
||||
- Add support for DMG palette customization.
|
||||
gambatte_sdl:
|
||||
- use std::map for parser
|
||||
- Don't bother hashing.
|
||||
- Add input config support.
|
||||
- Add joystick support.
|
||||
- Fix horrid "turbo can affect emulation" bug.
|
||||
- Add sw and yuv overlay scaling.
|
||||
- Use cond/mutex for thread syncing, RAII, refactor.
|
||||
- add option for sample rate choice
|
||||
- Add option to list valid input keys
|
||||
- don't die if audio fails
|
||||
gambatte_qt:
|
||||
- no point in filter being non-static anymore
|
||||
- use std::map for input vectors
|
||||
- remove unused unusedBool
|
||||
- Fix horrid "turbo can affect emulation" bug.
|
||||
- remove some useless optimizations
|
||||
- auto_ptr love.
|
||||
- support joystick hat.
|
||||
- nicer input handling.
|
||||
- Add sound dialog.
|
||||
- Add custom dev choice for oss, alsa engines.
|
||||
- Use rgb if available for xv.
|
||||
- Get rid of BAD_MATCH warnings for setting non-existent xv attributes.
|
||||
- make subblitters private nested classes
|
||||
- add reset action
|
||||
- Add support for DMG palette customization.
|
||||
- Add global buffer option for dsound engine
|
||||
|
||||
-- 0.2.0 -- 2007-09-05 --
|
||||
libgambatte:
|
||||
- fix 64-bit compile and segfault. Thanks to Nach for noticing.
|
||||
- Add zip support. Thanks to Nach for contributing nice, clear code
|
||||
- fix sound ch4 frequency calculation
|
||||
- Several PPU reads timings depend on wx. Thanks to franpa for noticing the
|
||||
corrupt line in The LoZ: Oracle of Seasons.
|
||||
- remove unused doubleSpeed parameter from m3ExtraCycles call
|
||||
gambatte_sdl:
|
||||
- Thread safety, bigger sound buffer
|
||||
- Compile on more platforms. Thanks to Thristian for the find.
|
||||
- actually increment iterator so the loop makes some sense (parser.cpp)
|
||||
gambatte_qt:
|
||||
- fix 64-bit compile. Thanks to Nach.
|
||||
- better license info for x11getprocaddress.cpp
|
||||
- initial joystick support, mostly using SDL's joystick code (separated from
|
||||
the rest of SDL)
|
||||
- use binary search for gb inputs.
|
||||
all:
|
||||
- make sure to use std:: despite sloppy compilers allowing omission. Thanks
|
||||
to blargg for the reminder.
|
||||
- get rid of some valgrind warnings. Thanks to Nach for noticing.
|
||||
hwtests:
|
||||
- add tests for wx effects on PPU read timings.
|
||||
build:
|
||||
- add -Wextra to default compile flags
|
||||
doc:
|
||||
- mention optional zlib dependency
|
||||
- additions to thanks section
|
||||
|
||||
-- 0.1.1 -- 2007-08-29 --
|
||||
libgambatte:
|
||||
- fix integer overflow in color conversion to rgb16
|
||||
- only accept valid filter indexes
|
||||
gambatte_sdl:
|
||||
- print version
|
||||
- print usage
|
||||
- support command line arguments.
|
||||
- add option for starting in full-screen
|
||||
- add option for using video filter
|
||||
gambatte_qt:
|
||||
- clean up obsolete includes.
|
||||
- directdraw: only use alpha if primary surface uses it.
|
||||
- add support for loading rom from porgam argument.
|
||||
- s/"a highly accurate"/"an accuracy-focused"/ in about box
|
||||
- gditoggler: fix unordered video mode listing
|
||||
build:
|
||||
- Support external CPPFLAGS
|
||||
- Use sdl-config
|
||||
doc:
|
||||
- fix silly wording in README about section
|
||||
- s/seperate/separate/
|
||||
- s/Automake/Make/
|
||||
- mention XShm dependency
|
||||
- mention sys/shm.h requirement
|
||||
- document key mapping better
|
||||
- s/"a highly accurate"/"an accuracy-focused"/
|
||||
- add man pages
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009, OpenEmu Team
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the OpenEmu Team nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "MyOpenGLView.h"
|
||||
#import "PrefController.h"
|
||||
|
||||
|
||||
@interface Controller : NSObject {
|
||||
|
||||
IBOutlet NSWindow* windowEmu;
|
||||
IBOutlet MyOpenGLView* viewEmu;
|
||||
IBOutlet NSMenuItem* stateS;
|
||||
IBOutlet NSMenuItem* stateL;
|
||||
IBOutlet NSMenuItem* pausePlay;
|
||||
IBOutlet NSMenuItem* resetItem;
|
||||
IBOutlet NSMenuItem* screenshotItem;
|
||||
IBOutlet NSMenuItem* closeItem;
|
||||
IBOutlet NSMenuItem* filtNoneItem;
|
||||
IBOutlet NSMenuItem* filt2xItem;
|
||||
IBOutlet NSMenuItem* filt3xItem;
|
||||
IBOutlet NSMenuItem* filtSai2xItem;
|
||||
IBOutlet NSMenuItem* filtHq2xItem;
|
||||
IBOutlet NSMenu* filtMenu;
|
||||
PrefController* windowPref;
|
||||
|
||||
}
|
||||
|
||||
-(IBAction) startLoad: (id) sender;
|
||||
-(IBAction) saveSaveState: (id) sender;
|
||||
-(IBAction) loadSaveState: (id) sender;
|
||||
-(IBAction) pauseEmu: (id) sender;
|
||||
-(IBAction) resetEmu: (id) sender;
|
||||
-(IBAction) closeWindow: (id) sender;
|
||||
-(IBAction) filterNone: (id) sender;
|
||||
-(IBAction) filter2x: (id) sender;
|
||||
-(IBAction) filter3x: (id) sender;
|
||||
-(IBAction) filterSai2x: (id) sender;
|
||||
-(IBAction) filterHq2x: (id) sender;
|
||||
-(IBAction) screenshot: (id) sender;
|
||||
-(IBAction) displayPref: (id) sender;
|
||||
- (void) changeFilter: (int) newFilt;
|
||||
- (void) changeVolume: (float) newVolume;
|
||||
- (NSBitmapImageRep*) getRawData;
|
||||
- (void) activateMenus: (bool) will;
|
||||
|
||||
@end
|
||||
@@ -1,35 +0,0 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf330
|
||||
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
|
||||
|
||||
\f0\b\fs24 \cf0 Core:
|
||||
\b0 \
|
||||
Sindre Aamas
|
||||
\b \
|
||||
\
|
||||
Mac Port:
|
||||
\b0 \
|
||||
Ben Decavel\
|
||||
\
|
||||
|
||||
\b Testing:
|
||||
\b0 \
|
||||
Hopefully not nobody\
|
||||
\
|
||||
|
||||
\b Documentation:
|
||||
\b0 \
|
||||
Whooops!\
|
||||
\
|
||||
|
||||
\b Webdesign/Webhosting:
|
||||
\b0 \
|
||||
Sky\
|
||||
\
|
||||
|
||||
\b With special thanks to:
|
||||
\b0 \
|
||||
Josh Weinberg\
|
||||
(for all your code I ripped off)\
|
||||
}
|
||||
Binary file not shown.
+536
-318
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Copyright (c) 2009, OpenEmu Team
|
||||
|
||||
Copyright (c) 2015, OpenEmu Team
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
@@ -11,7 +11,7 @@
|
||||
* Neither the name of the OpenEmu Team nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
@@ -22,263 +22,162 @@
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
*/
|
||||
|
||||
#import "GBGameCore.h"
|
||||
#import <OpenEmuBase/OERingBuffer.h>
|
||||
#import "OEGBSystemResponderClient.h"
|
||||
#import <OpenGL/gl.h>
|
||||
|
||||
#include "libretro.h"
|
||||
#include <sstream>
|
||||
#include "gambatte.h"
|
||||
#include "gbcpalettes.h"
|
||||
#include "resamplerinfo.h"
|
||||
#include "resampler.h"
|
||||
|
||||
#define OptionDefault(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @YES, }
|
||||
#define Option(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, }
|
||||
#define OptionIndented(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, OEGameCoreDisplayModeIndentationLevelKey : @(1), }
|
||||
#define OptionToggleable(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, OEGameCoreDisplayModeAllowsToggleKey : @YES, }
|
||||
#define OptionToggleableNoSave(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, OEGameCoreDisplayModeAllowsToggleKey : @YES, OEGameCoreDisplayModeDisallowPrefSaveKey : @YES, }
|
||||
#define Label(_NAME_) @{ OEGameCoreDisplayModeLabelKey : _NAME_, }
|
||||
#define SeparatorItem() @{ OEGameCoreDisplayModeSeparatorItemKey : @"",}
|
||||
|
||||
gambatte::GB gb;
|
||||
Resampler *resampler;
|
||||
uint32_t pad[OEGBButtonCount];
|
||||
|
||||
class GetInput : public gambatte::InputGetter
|
||||
{
|
||||
public:
|
||||
unsigned operator()()
|
||||
{
|
||||
return pad[0];
|
||||
}
|
||||
} static GetInput;
|
||||
|
||||
@interface GBGameCore () <OEGBSystemResponderClient>
|
||||
{
|
||||
uint32_t *videoBuffer;
|
||||
int videoWidth, videoHeight;
|
||||
int16_t pad[2][8];
|
||||
NSString *romName;
|
||||
double sampleRate;
|
||||
uint32_t *_videoBuffer;
|
||||
uint32_t *_inSoundBuffer;
|
||||
int16_t *_outSoundBuffer;
|
||||
double _sampleRate;
|
||||
NSMutableDictionary <NSString *, NSNumber *> *_cheatList;
|
||||
NSMutableArray <NSMutableDictionary <NSString *, id> *> *_availableDisplayModes;
|
||||
}
|
||||
|
||||
- (void)applyCheat:(NSString *)code;
|
||||
|
||||
- (void)loadDisplayModeOptions;
|
||||
- (NSString *)gameInternalName;
|
||||
- (BOOL)gameHasInternalPalette;
|
||||
- (void)loadPalette;
|
||||
- (void)loadPaletteDefault;
|
||||
- (void)changePalette:(NSString *)palette;
|
||||
|
||||
@end
|
||||
|
||||
NSUInteger GBEmulatorValues[] = { RETRO_DEVICE_ID_JOYPAD_UP, RETRO_DEVICE_ID_JOYPAD_DOWN, RETRO_DEVICE_ID_JOYPAD_LEFT, RETRO_DEVICE_ID_JOYPAD_RIGHT, RETRO_DEVICE_ID_JOYPAD_A, RETRO_DEVICE_ID_JOYPAD_B, RETRO_DEVICE_ID_JOYPAD_START, RETRO_DEVICE_ID_JOYPAD_SELECT };
|
||||
NSString *GBEmulatorKeys[] = { @"Joypad@ Up", @"Joypad@ Down", @"Joypad@ Left", @"Joypad@ Right", @"Joypad@ 1", @"Joypad@ 2", @"Joypad@ Run", @"Joypad@ Select"};
|
||||
|
||||
@implementation GBGameCore
|
||||
|
||||
static __weak GBGameCore *_current;
|
||||
|
||||
static void audio_callback(int16_t left, int16_t right)
|
||||
{
|
||||
GET_CURRENT_AND_RETURN();
|
||||
|
||||
[[current ringBufferAtIndex:0] write:&left maxLength:2];
|
||||
[[current ringBufferAtIndex:0] write:&right maxLength:2];
|
||||
}
|
||||
|
||||
static size_t audio_batch_callback(const int16_t *data, size_t frames)
|
||||
{
|
||||
GET_CURRENT_AND_RETURN(frames);
|
||||
|
||||
[[current ringBufferAtIndex:0] write:data maxLength:frames << 2];
|
||||
return frames;
|
||||
}
|
||||
|
||||
static void video_callback(const void *data, unsigned width, unsigned height, size_t pitch)
|
||||
{
|
||||
GET_CURRENT_AND_RETURN();
|
||||
|
||||
current->videoWidth = width;
|
||||
current->videoHeight = height;
|
||||
|
||||
dispatch_queue_t the_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
|
||||
dispatch_apply(height, the_queue, ^(size_t y){
|
||||
const uint32_t *src = (uint32_t*)data + y * (pitch >> 2); //pitch is in bytes not pixels
|
||||
uint32_t *dst = current->videoBuffer + y * 160;
|
||||
|
||||
memcpy(dst, src, sizeof(uint32_t)*width);
|
||||
});
|
||||
}
|
||||
|
||||
static void input_poll_callback(void)
|
||||
{
|
||||
//NSLog(@"poll callback");
|
||||
}
|
||||
|
||||
static int16_t input_state_callback(unsigned port, unsigned device, unsigned index, unsigned id)
|
||||
{
|
||||
GET_CURRENT_AND_RETURN(0);
|
||||
|
||||
if(port == 0 & device == RETRO_DEVICE_JOYPAD)
|
||||
return current->pad[0][id];
|
||||
else if(port == 1 & device == RETRO_DEVICE_JOYPAD)
|
||||
return current->pad[1][id];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool environment_callback(unsigned cmd, void *data)
|
||||
{
|
||||
switch(cmd)
|
||||
{
|
||||
case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY :
|
||||
{
|
||||
// FIXME: Build a path in a more appropriate place
|
||||
NSString *appSupportPath = [NSString pathWithComponents:@[
|
||||
[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject],
|
||||
@"OpenEmu", @"BIOS"]];
|
||||
|
||||
*(const char **)data = [appSupportPath UTF8String];
|
||||
NSLog(@"Environ SYSTEM_DIRECTORY: \"%@\".\n", appSupportPath);
|
||||
break;
|
||||
}
|
||||
default :
|
||||
NSLog(@"Environ UNSUPPORTED (#%u).\n", cmd);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void loadSaveFile(const char* path, int type)
|
||||
{
|
||||
FILE *file;
|
||||
|
||||
file = fopen(path, "rb");
|
||||
if(file == NULL) return;
|
||||
|
||||
size_t size = retro_get_memory_size(type);
|
||||
void *data = retro_get_memory_data(type);
|
||||
|
||||
if(size == 0 || data == NULL)
|
||||
{
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
int rc = fread(data, sizeof(uint8_t), size, file);
|
||||
if(rc != size) NSLog(@"Couldn't load save file: %s.", path);
|
||||
else NSLog(@"Loaded save file: %s", path);
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
static void writeSaveFile(const char* path, int type)
|
||||
{
|
||||
size_t size = retro_get_memory_size(type);
|
||||
void *data = retro_get_memory_data(type);
|
||||
|
||||
if(data != NULL && size > 0)
|
||||
{
|
||||
FILE *file = fopen(path, "wb");
|
||||
if(file != NULL)
|
||||
{
|
||||
NSLog(@"Saving state %s. Size: %d bytes.", path, (int)size);
|
||||
retro_serialize(data, size);
|
||||
if(fwrite(data, sizeof(uint8_t), size, file) != size)
|
||||
NSLog(@"Did not save state properly.");
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (oneway void)didPushGBButton:(OEGBButton)button;
|
||||
{
|
||||
pad[0][GBEmulatorValues[button]] = 1;
|
||||
}
|
||||
|
||||
- (oneway void)didReleaseGBButton:(OEGBButton)button;
|
||||
{
|
||||
pad[0][GBEmulatorValues[button]] = 0;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if((self = [super init]))
|
||||
{
|
||||
videoBuffer = (uint32_t*)malloc(160 * 144 * 4);
|
||||
_inSoundBuffer = (uint32_t *)malloc(2064 * 2 * 4);
|
||||
_outSoundBuffer = (int16_t *)malloc(2064 * 2 * 2);
|
||||
_cheatList = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
_current = self;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark Exectuion
|
||||
|
||||
- (void)executeFrame
|
||||
- (void)dealloc
|
||||
{
|
||||
[self executeFrameSkippingFrame:NO];
|
||||
free(_videoBuffer);
|
||||
free(_inSoundBuffer);
|
||||
free(_outSoundBuffer);
|
||||
}
|
||||
|
||||
- (void)executeFrameSkippingFrame: (BOOL) skip
|
||||
{
|
||||
retro_run();
|
||||
}
|
||||
# pragma mark - Execution
|
||||
|
||||
- (BOOL)loadFileAtPath:(NSString *)path error:(NSError **)error
|
||||
{
|
||||
memset(pad, 0, sizeof(int16_t) * 9);
|
||||
memset(pad, 0, sizeof(pad));
|
||||
|
||||
const void *data;
|
||||
size_t size;
|
||||
romName = [path copy];
|
||||
// Set battery save dir
|
||||
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:self.batterySavesDirectoryPath];
|
||||
[[NSFileManager defaultManager] createDirectoryAtURL:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
gb.setSaveDir(batterySavesDirectory.fileSystemRepresentation);
|
||||
|
||||
//load cart, read bytes, get length
|
||||
NSData* dataObj = [NSData dataWithContentsOfFile:[romName stringByStandardizingPath]];
|
||||
if(dataObj == nil) return false;
|
||||
size = [dataObj length];
|
||||
data = (uint8_t*)[dataObj bytes];
|
||||
const char *meta = NULL;
|
||||
// Set input state callback
|
||||
gb.setInputGetter(&GetInput);
|
||||
|
||||
retro_set_environment(environment_callback);
|
||||
retro_init();
|
||||
// Setup resampler
|
||||
double fps = 4194304.0 / 70224.0;
|
||||
double inSampleRate = fps * 35112; // 2097152
|
||||
|
||||
retro_set_audio_sample(audio_callback);
|
||||
retro_set_audio_sample_batch(audio_batch_callback);
|
||||
retro_set_video_refresh(video_callback);
|
||||
retro_set_input_poll(input_poll_callback);
|
||||
retro_set_input_state(input_state_callback);
|
||||
// 2 = "Very high quality (polyphase FIR)", see resamplerinfo.cpp
|
||||
resampler = ResamplerInfo::get(2).create(inSampleRate, 48000.0, 2 * 2064);
|
||||
|
||||
unsigned long mul, div;
|
||||
resampler->exactRatio(mul, div);
|
||||
|
||||
const char *fullPath = [path UTF8String];
|
||||
double outSampleRate = inSampleRate * mul / div;
|
||||
_sampleRate = outSampleRate; // 47994.326636
|
||||
|
||||
struct retro_game_info gameInfo = {NULL};
|
||||
gameInfo.path = fullPath;
|
||||
gameInfo.data = data;
|
||||
gameInfo.size = size;
|
||||
gameInfo.meta = meta;
|
||||
if (gb.load(path.fileSystemRepresentation) != 0)
|
||||
return NO;
|
||||
|
||||
if(retro_load_game(&gameInfo))
|
||||
{
|
||||
NSString *path = romName;
|
||||
NSString *extensionlessFilename = [[path lastPathComponent] stringByDeletingPathExtension];
|
||||
[self loadDisplayModeOptions];
|
||||
|
||||
NSString *batterySavesDirectory = [self batterySavesDirectoryPath];
|
||||
|
||||
if([batterySavesDirectory length] != 0)
|
||||
{
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:NULL];
|
||||
|
||||
NSString *filePath = [batterySavesDirectory stringByAppendingPathComponent:[extensionlessFilename stringByAppendingPathExtension:@"sav"]];
|
||||
|
||||
NSString *filePathRTC = [batterySavesDirectory stringByAppendingPathComponent:[extensionlessFilename stringByAppendingPathExtension:@"rtc"]];
|
||||
|
||||
loadSaveFile([filePath UTF8String], RETRO_MEMORY_SAVE_RAM);
|
||||
loadSaveFile([filePathRTC UTF8String], RETRO_MEMORY_RTC);
|
||||
}
|
||||
|
||||
struct retro_system_av_info avInfo;
|
||||
retro_get_system_av_info(&avInfo);
|
||||
|
||||
frameInterval = avInfo.timing.fps;
|
||||
sampleRate = avInfo.timing.sample_rate;
|
||||
|
||||
//retro_set_controller_port_device(SNES_PORT_1, RETRO_DEVICE_JOYPAD);
|
||||
|
||||
retro_get_region();
|
||||
|
||||
retro_run();
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark Video
|
||||
|
||||
- (const void *)videoBuffer
|
||||
- (void)executeFrame
|
||||
{
|
||||
return videoBuffer;
|
||||
size_t samples = 2064;
|
||||
|
||||
while (gb.runFor(_videoBuffer, 160, _inSoundBuffer, samples) == -1) {
|
||||
[self outputAudio:samples];
|
||||
samples = 2064;
|
||||
}
|
||||
|
||||
[self outputAudio:samples];
|
||||
}
|
||||
|
||||
- (void)resetEmulation
|
||||
{
|
||||
gb.reset();
|
||||
}
|
||||
|
||||
- (void)stopEmulation
|
||||
{
|
||||
gb.saveSavedata();
|
||||
|
||||
delete resampler;
|
||||
|
||||
[super stopEmulation];
|
||||
}
|
||||
|
||||
- (NSTimeInterval)frameInterval
|
||||
{
|
||||
return 59.727501;
|
||||
}
|
||||
|
||||
# pragma mark - Video
|
||||
|
||||
- (const void *)getVideoBufferWithHint:(void *)hint
|
||||
{
|
||||
if (!hint) {
|
||||
if (!_videoBuffer) _videoBuffer = (uint32_t *)malloc(160 * 144 * 4);
|
||||
hint = _videoBuffer;
|
||||
}
|
||||
return _videoBuffer = (uint32_t*)hint;
|
||||
}
|
||||
|
||||
- (OEIntRect)screenRect
|
||||
{
|
||||
return OEIntRectMake(0, 0, videoWidth, videoHeight);
|
||||
return OEIntRectMake(0, 0, 160, 144);
|
||||
}
|
||||
|
||||
- (OEIntSize)bufferSize
|
||||
@@ -291,43 +190,6 @@ static void writeSaveFile(const char* path, int type)
|
||||
return OEIntSizeMake(10, 9);
|
||||
}
|
||||
|
||||
- (void)resetEmulation
|
||||
{
|
||||
retro_reset();
|
||||
}
|
||||
|
||||
- (void)stopEmulation
|
||||
{
|
||||
NSString *path = romName;
|
||||
NSString *extensionlessFilename = [[path lastPathComponent] stringByDeletingPathExtension];
|
||||
|
||||
NSString *batterySavesDirectory = [self batterySavesDirectoryPath];
|
||||
|
||||
if([batterySavesDirectory length] != 0)
|
||||
{
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:NULL];
|
||||
|
||||
NSLog(@"Trying to save SRAM");
|
||||
|
||||
NSString *filePath = [batterySavesDirectory stringByAppendingPathComponent:[extensionlessFilename stringByAppendingPathExtension:@"sav"]];
|
||||
|
||||
NSString *filePathRTC = [batterySavesDirectory stringByAppendingPathComponent:[extensionlessFilename stringByAppendingPathExtension:@"rtc"]];
|
||||
|
||||
writeSaveFile([filePath UTF8String], RETRO_MEMORY_SAVE_RAM);
|
||||
writeSaveFile([filePathRTC UTF8String], RETRO_MEMORY_RTC);
|
||||
}
|
||||
|
||||
NSLog(@"gb term");
|
||||
retro_unload_game();
|
||||
retro_deinit();
|
||||
[super stopEmulation];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
free(videoBuffer);
|
||||
}
|
||||
|
||||
- (GLenum)pixelFormat
|
||||
{
|
||||
return GL_BGRA;
|
||||
@@ -338,19 +200,11 @@ static void writeSaveFile(const char* path, int type)
|
||||
return GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||
}
|
||||
|
||||
- (GLenum)internalPixelFormat
|
||||
{
|
||||
return GL_RGB8;
|
||||
}
|
||||
# pragma mark - Audio
|
||||
|
||||
- (double)audioSampleRate
|
||||
{
|
||||
return sampleRate ? sampleRate : 48000;
|
||||
}
|
||||
|
||||
- (NSTimeInterval)frameInterval
|
||||
{
|
||||
return frameInterval ? frameInterval : 2097152./35112.; // 59.7
|
||||
return _sampleRate;
|
||||
}
|
||||
|
||||
- (NSUInteger)channelCount
|
||||
@@ -358,73 +212,437 @@ static void writeSaveFile(const char* path, int type)
|
||||
return 2;
|
||||
}
|
||||
|
||||
# pragma mark - Save States
|
||||
|
||||
- (void)saveStateToFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block
|
||||
{
|
||||
int serial_size = retro_serialize_size();
|
||||
NSMutableData *stateData = [NSMutableData dataWithLength:serial_size];
|
||||
|
||||
if(!retro_serialize([stateData mutableBytes], serial_size))
|
||||
{
|
||||
NSError *error = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotSaveStateError userInfo:@{
|
||||
NSLocalizedDescriptionKey : @"Save state data could not be written",
|
||||
NSLocalizedRecoverySuggestionErrorKey : @"The emulator could not write the state data."
|
||||
}];
|
||||
block(NO, error);
|
||||
return;
|
||||
}
|
||||
|
||||
__autoreleasing NSError *error = nil;
|
||||
BOOL success = [stateData writeToFile:fileName options:NSDataWritingAtomic error:&error];
|
||||
|
||||
block(success, success ? nil : error);
|
||||
int success = gb.saveState(0, 0, fileName.fileSystemRepresentation);
|
||||
if(block) block(success==1, nil);
|
||||
}
|
||||
|
||||
- (void)loadStateFromFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block
|
||||
{
|
||||
__autoreleasing NSError *error = nil;
|
||||
NSData *data = [NSData dataWithContentsOfFile:fileName options:NSDataReadingMappedIfSafe | NSDataReadingUncached error:&error];
|
||||
|
||||
if(data == nil)
|
||||
{
|
||||
block(NO, error);
|
||||
return;
|
||||
}
|
||||
|
||||
int serial_size = retro_serialize_size();
|
||||
if(serial_size != [data length])
|
||||
{
|
||||
NSError *error = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreStateHasWrongSizeError userInfo:@{
|
||||
NSLocalizedDescriptionKey : @"Save state has wrong file size.",
|
||||
NSLocalizedRecoverySuggestionErrorKey : [NSString stringWithFormat:@"The size of the file %@ does not have the right size, %d expected, got: %ld.", fileName, serial_size, [data length]],
|
||||
}];
|
||||
block(NO, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!retro_unserialize([data bytes], serial_size))
|
||||
{
|
||||
NSError *error = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotLoadStateError userInfo:@{
|
||||
NSLocalizedDescriptionKey : @"The save state data could not be read",
|
||||
NSLocalizedRecoverySuggestionErrorKey : [NSString stringWithFormat:@"Could not read the file state in %@.", fileName]
|
||||
}];
|
||||
block(NO, error);
|
||||
return;
|
||||
}
|
||||
|
||||
block(YES, nil);
|
||||
int success = gb.loadState(fileName.fileSystemRepresentation);
|
||||
if(block) block(success==1, nil);
|
||||
}
|
||||
|
||||
- (NSData *)serializeStateWithError:(NSError **)outError
|
||||
{
|
||||
std::stringstream stream(std::ios::in|std::ios::out|std::ios::binary);
|
||||
|
||||
if(gb.serializeState(stream)) {
|
||||
stream.seekg(0, std::ios::end);
|
||||
NSUInteger length = stream.tellg();
|
||||
stream.seekg(0, std::ios::beg);
|
||||
|
||||
char *bytes = (char *)malloc(length);
|
||||
stream.read(bytes, length);
|
||||
|
||||
return [NSData dataWithBytesNoCopy:bytes length:length];
|
||||
}
|
||||
|
||||
if(outError) {
|
||||
*outError = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotSaveStateError userInfo:@{
|
||||
NSLocalizedDescriptionKey : @"Save state data could not be written",
|
||||
NSLocalizedRecoverySuggestionErrorKey : @"The emulator could not write the state data."
|
||||
}];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)deserializeState:(NSData *)state withError:(NSError **)outError
|
||||
{
|
||||
std::stringstream stream(std::ios::in|std::ios::out|std::ios::binary);
|
||||
|
||||
char const *bytes = (char const *)(state.bytes);
|
||||
std::streamsize size = state.length;
|
||||
stream.write(bytes, size);
|
||||
|
||||
if(gb.deserializeState(stream))
|
||||
return YES;
|
||||
|
||||
if(outError) {
|
||||
*outError = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotLoadStateError userInfo:@{
|
||||
NSLocalizedDescriptionKey : @"The save state data could not be read",
|
||||
NSLocalizedRecoverySuggestionErrorKey : @"Could not load data from the save state"
|
||||
}];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
# pragma mark - Input
|
||||
|
||||
const int GBMap[] = {gambatte::InputGetter::UP, gambatte::InputGetter::DOWN, gambatte::InputGetter::LEFT, gambatte::InputGetter::RIGHT, gambatte::InputGetter::A, gambatte::InputGetter::B, gambatte::InputGetter::START, gambatte::InputGetter::SELECT};
|
||||
- (oneway void)didPushGBButton:(OEGBButton)button;
|
||||
{
|
||||
pad[0] |= GBMap[button];
|
||||
}
|
||||
|
||||
- (oneway void)didReleaseGBButton:(OEGBButton)button;
|
||||
{
|
||||
pad[0] &= ~GBMap[button];
|
||||
}
|
||||
|
||||
#pragma mark - Cheats
|
||||
|
||||
- (void)setCheat:(NSString *)code setType:(NSString *)type setEnabled:(BOOL)enabled
|
||||
{
|
||||
if ([type isEqual: @"Unknown"] && [code rangeOfString:@"-"].location == NSNotFound)
|
||||
type = @"GameShark";
|
||||
|
||||
if ([type isEqual: @"Unknown"] && [code rangeOfString:@"-"].location != NSNotFound)
|
||||
type = @"Game Genie";
|
||||
|
||||
const char *cheatCode = [code UTF8String];
|
||||
const char *cheatType = [type UTF8String];
|
||||
retro_cheat_set(nil, enabled, cheatCode, cheatType);
|
||||
// Sanitize
|
||||
code = [code stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
|
||||
|
||||
// Gambatte expects cheats UPPERCASE
|
||||
code = code.uppercaseString;
|
||||
|
||||
// Remove any spaces
|
||||
code = [code stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||
|
||||
if (enabled)
|
||||
_cheatList[code] = @YES;
|
||||
else
|
||||
[_cheatList removeObjectForKey:code];
|
||||
|
||||
NSMutableArray <NSString *> *combinedGameSharkCodes = [NSMutableArray array];
|
||||
NSMutableArray <NSString *> *combinedGameGenieCodes = [NSMutableArray array];
|
||||
|
||||
// Gambatte expects all cheats in one combined string per-type e.g. 01xxxxxx+01xxxxxx
|
||||
// Add enabled per-type cheats to arrays and later join them all by a '+' separator
|
||||
for (NSString *key in _cheatList)
|
||||
{
|
||||
if ([_cheatList[key] boolValue])
|
||||
{
|
||||
// GameShark
|
||||
if (![key containsString:@"-"])
|
||||
[combinedGameSharkCodes addObject:key];
|
||||
// Game Genie
|
||||
else if ([key containsString:@"-"])
|
||||
[combinedGameGenieCodes addObject:key];
|
||||
}
|
||||
}
|
||||
|
||||
// Apply combined cheats or force a final reset if all cheats are disabled
|
||||
[self applyCheat:combinedGameSharkCodes.count != 0 ? [combinedGameSharkCodes componentsJoinedByString:@"+"] : @"0"];
|
||||
[self applyCheat:combinedGameGenieCodes.count != 0 ? [combinedGameGenieCodes componentsJoinedByString:@"+"] : @"0-"];
|
||||
}
|
||||
|
||||
# pragma mark - Display Mode
|
||||
|
||||
- (NSArray <NSDictionary <NSString *, id> *> *)displayModes
|
||||
{
|
||||
if (_availableDisplayModes.count == 0)
|
||||
{
|
||||
_availableDisplayModes = [NSMutableArray array];
|
||||
|
||||
NSArray <NSDictionary <NSString *, id> *> *availableModesWithDefault;
|
||||
|
||||
if (gb.isCgb())
|
||||
{
|
||||
availableModesWithDefault =
|
||||
@[
|
||||
Label(@"Color Correction"),
|
||||
OptionDefault(@"Default", @"colorCorrection"),
|
||||
Option(@"Modern", @"colorCorrection"),
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
availableModesWithDefault =
|
||||
@[
|
||||
Option(@"Internal", @"palette"),
|
||||
Option(@"Grayscale", @"palette"),
|
||||
Option(@"Greenscale", @"palette"),
|
||||
Option(@"Pocket", @"palette"),
|
||||
SeparatorItem(),
|
||||
Label(@"GBC Palettes"),
|
||||
Option(@"Blue", @"palette"),
|
||||
Option(@"Dark Blue", @"palette"),
|
||||
Option(@"Green", @"palette"),
|
||||
Option(@"Dark Green", @"palette"),
|
||||
Option(@"Brown", @"palette"),
|
||||
Option(@"Dark Brown", @"palette"),
|
||||
Option(@"Red", @"palette"),
|
||||
Option(@"Yellow", @"palette"),
|
||||
Option(@"Orange", @"palette"),
|
||||
Option(@"Pastel Mix", @"palette"),
|
||||
Option(@"Inverted", @"palette"),
|
||||
];
|
||||
}
|
||||
|
||||
// Deep mutable copy
|
||||
_availableDisplayModes = (NSMutableArray *)CFBridgingRelease(CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFArrayRef)availableModesWithDefault, kCFPropertyListMutableContainers));
|
||||
|
||||
if (!gb.isCgb() && ![self gameHasInternalPalette])
|
||||
[_availableDisplayModes removeObjectAtIndex:0];
|
||||
}
|
||||
|
||||
return [_availableDisplayModes copy];
|
||||
}
|
||||
|
||||
- (void)changeDisplayWithMode:(NSString *)displayMode
|
||||
{
|
||||
// NOTE: This is a more complex implementation to serve as an example for handling submenus,
|
||||
// toggleable options and multiple groups of mutually exclusive options.
|
||||
|
||||
if (_availableDisplayModes.count == 0)
|
||||
[self displayModes];
|
||||
|
||||
// First check if 'displayMode' is toggleable and grab its preference key
|
||||
BOOL isDisplayModeToggleable = NO;
|
||||
BOOL isValidDisplayMode = NO;
|
||||
BOOL displayModeState = NO;
|
||||
NSString *displayModePrefKey;
|
||||
|
||||
for (NSDictionary *modeDict in _availableDisplayModes)
|
||||
{
|
||||
if ([modeDict[OEGameCoreDisplayModeNameKey] isEqualToString:displayMode])
|
||||
{
|
||||
displayModeState = [modeDict[OEGameCoreDisplayModeStateKey] boolValue];
|
||||
displayModePrefKey = modeDict[OEGameCoreDisplayModePrefKeyNameKey];
|
||||
isDisplayModeToggleable = [modeDict[OEGameCoreDisplayModeAllowsToggleKey] boolValue];
|
||||
isValidDisplayMode = YES;
|
||||
break;
|
||||
}
|
||||
// Submenu Items
|
||||
for (NSDictionary *subModeDict in modeDict[OEGameCoreDisplayModeGroupItemsKey])
|
||||
{
|
||||
if ([subModeDict[OEGameCoreDisplayModeNameKey] isEqualToString:displayMode])
|
||||
{
|
||||
displayModeState = [subModeDict[OEGameCoreDisplayModeStateKey] boolValue];
|
||||
displayModePrefKey = subModeDict[OEGameCoreDisplayModePrefKeyNameKey];
|
||||
isDisplayModeToggleable = [subModeDict[OEGameCoreDisplayModeAllowsToggleKey] boolValue];
|
||||
isValidDisplayMode = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Disallow a 'displayMode' not found in _availableDisplayModes
|
||||
if (!isValidDisplayMode)
|
||||
return;
|
||||
|
||||
// Handle option state changes
|
||||
for (NSMutableDictionary *optionDict in _availableDisplayModes)
|
||||
{
|
||||
NSString *modeName = optionDict[OEGameCoreDisplayModeNameKey];
|
||||
NSString *prefKey = optionDict[OEGameCoreDisplayModePrefKeyNameKey];
|
||||
|
||||
if (!modeName && !optionDict[OEGameCoreDisplayModeGroupNameKey])
|
||||
continue;
|
||||
// Mutually exclusive option state change
|
||||
else if ([modeName isEqualToString:displayMode] && !isDisplayModeToggleable)
|
||||
optionDict[OEGameCoreDisplayModeStateKey] = @YES;
|
||||
// Reset mutually exclusive options that are the same prefs group as 'displayMode'
|
||||
else if (!isDisplayModeToggleable && [prefKey isEqualToString:displayModePrefKey])
|
||||
optionDict[OEGameCoreDisplayModeStateKey] = @NO;
|
||||
// Toggleable option state change
|
||||
else if ([modeName isEqualToString:displayMode] && isDisplayModeToggleable)
|
||||
optionDict[OEGameCoreDisplayModeStateKey] = @(!displayModeState);
|
||||
// Submenu group
|
||||
else if (optionDict[OEGameCoreDisplayModeGroupNameKey])
|
||||
{
|
||||
// Submenu items
|
||||
for (NSMutableDictionary *subOptionDict in optionDict[OEGameCoreDisplayModeGroupItemsKey])
|
||||
{
|
||||
NSString *modeName = subOptionDict[OEGameCoreDisplayModeNameKey];
|
||||
NSString *prefKey = subOptionDict[OEGameCoreDisplayModePrefKeyNameKey];
|
||||
|
||||
if (!modeName)
|
||||
continue;
|
||||
// Mutually exclusive option state change
|
||||
else if ([modeName isEqualToString:displayMode] && !isDisplayModeToggleable)
|
||||
subOptionDict[OEGameCoreDisplayModeStateKey] = @YES;
|
||||
// Reset mutually exclusive options that are the same prefs group as 'displayMode'
|
||||
else if (!isDisplayModeToggleable && [prefKey isEqualToString:displayModePrefKey])
|
||||
subOptionDict[OEGameCoreDisplayModeStateKey] = @NO;
|
||||
// Toggleable option state change
|
||||
else if ([modeName isEqualToString:displayMode] && isDisplayModeToggleable)
|
||||
subOptionDict[OEGameCoreDisplayModeStateKey] = @(!displayModeState);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the new palette
|
||||
if ([displayModePrefKey isEqualToString:@"palette"])
|
||||
[self changePalette:displayMode];
|
||||
else if ([displayModePrefKey isEqualToString:@"colorCorrection"])
|
||||
gb.setCgbColorCorrection([displayMode isEqual:@"Modern"] ? 1 : 0);
|
||||
}
|
||||
|
||||
# pragma mark - Misc Helper Methods
|
||||
|
||||
- (void)outputAudio:(size_t)frames
|
||||
{
|
||||
if (!frames)
|
||||
return;
|
||||
|
||||
size_t len = resampler->resample(_outSoundBuffer, reinterpret_cast<const int16_t *>(_inSoundBuffer), frames);
|
||||
|
||||
if (len)
|
||||
[[self audioBufferAtIndex:0] write:_outSoundBuffer maxLength:len << 2];
|
||||
}
|
||||
|
||||
- (void)applyCheat:(NSString *)code
|
||||
{
|
||||
std::string s = [code UTF8String];
|
||||
if (s.find("-") != std::string::npos)
|
||||
gb.setGameGenie(s);
|
||||
else
|
||||
gb.setGameShark(s);
|
||||
}
|
||||
|
||||
- (void)loadDisplayModeOptions
|
||||
{
|
||||
if (gb.isCgb())
|
||||
{
|
||||
// Restore color correction
|
||||
NSString *lastColorCorrection = self.displayModeInfo[@"colorCorrection"] ?: @"Default";
|
||||
[self changeDisplayWithMode:lastColorCorrection];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load built-in GBC palette for monochrome games if supported
|
||||
[self loadPalette];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)gameInternalName
|
||||
{
|
||||
NSString *title = [NSString stringWithUTF8String:gb.romTitle().c_str()];
|
||||
return title;
|
||||
}
|
||||
|
||||
- (BOOL)gameHasInternalPalette
|
||||
{
|
||||
unsigned short *gbc_bios_palette = NULL;
|
||||
NSString *title = [self gameInternalName];
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcTitlePal(title.UTF8String));
|
||||
|
||||
return gbc_bios_palette != 0 ? YES : NO;
|
||||
}
|
||||
|
||||
- (void)loadPalette
|
||||
{
|
||||
// Only temporary, so core doesn't crash on an older OpenEmu version
|
||||
if (![self respondsToSelector:@selector(displayModeInfo)])
|
||||
{
|
||||
[self loadPaletteDefault];
|
||||
}
|
||||
// No previous palette saved, set a default
|
||||
else if (self.displayModeInfo[@"palette"] == nil)
|
||||
{
|
||||
[self loadPaletteDefault];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSString *lastPalette = self.displayModeInfo[@"palette"];
|
||||
// Don't try to load "Internal" palette for a game without one
|
||||
if ([lastPalette isEqualToString:@"Internal"] && ![self gameHasInternalPalette])
|
||||
[self changeDisplayWithMode:@"Grayscale"];
|
||||
else
|
||||
[self changeDisplayWithMode:lastPalette];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadPaletteDefault
|
||||
{
|
||||
if ([self gameHasInternalPalette])
|
||||
// load a GBC BIOS builtin palette
|
||||
[self changeDisplayWithMode:@"Internal"];
|
||||
else
|
||||
// no custom palette found, load the default (Original Grayscale)
|
||||
[self changeDisplayWithMode:@"Grayscale"];
|
||||
}
|
||||
|
||||
- (void)changePalette:(NSString *)palette
|
||||
{
|
||||
NSDictionary <NSString *, NSString *> *paletteNames =
|
||||
@{
|
||||
@"Internal" : @"Internal",
|
||||
@"Grayscale" : @"GBC - Grayscale",
|
||||
@"Greenscale" : @"Greenscale",
|
||||
@"Pocket" : @"Pocket",
|
||||
@"Blue" : @"GBC - Blue",
|
||||
@"Dark Blue" : @"GBC - Dark Blue",
|
||||
@"Green" : @"GBC - Green",
|
||||
@"Dark Green" : @"GBC - Dark Green",
|
||||
@"Brown" : @"GBC - Brown",
|
||||
@"Dark Brown" : @"GBC - Dark Brown",
|
||||
@"Red" : @"GBC - Red",
|
||||
@"Yellow" : @"GBC - Yellow",
|
||||
@"Orange" : @"GBC - Orange",
|
||||
@"Pastel Mix" : @"GBC - Pastel Mix",
|
||||
@"Inverted" : @"GBC - Inverted",
|
||||
};
|
||||
|
||||
palette = paletteNames[palette];
|
||||
unsigned short *gbc_bios_palette = NULL;
|
||||
|
||||
if ([palette isEqualToString:@"Internal"])
|
||||
{
|
||||
NSString *title = [self gameInternalName];
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcTitlePal(title.UTF8String));
|
||||
}
|
||||
else if ([palette isEqualToString:@"Greenscale"])
|
||||
{
|
||||
// GB Pea Soup Green
|
||||
gb.setDmgPaletteColor(0, 0, 8369468);
|
||||
gb.setDmgPaletteColor(0, 1, 6728764);
|
||||
gb.setDmgPaletteColor(0, 2, 3629872);
|
||||
gb.setDmgPaletteColor(0, 3, 3223857);
|
||||
gb.setDmgPaletteColor(1, 0, 8369468);
|
||||
gb.setDmgPaletteColor(1, 1, 6728764);
|
||||
gb.setDmgPaletteColor(1, 2, 3629872);
|
||||
gb.setDmgPaletteColor(1, 3, 3223857);
|
||||
gb.setDmgPaletteColor(2, 0, 8369468);
|
||||
gb.setDmgPaletteColor(2, 1, 6728764);
|
||||
gb.setDmgPaletteColor(2, 2, 3629872);
|
||||
gb.setDmgPaletteColor(2, 3, 3223857);
|
||||
return;
|
||||
}
|
||||
else if ([palette isEqualToString:@"Pocket"])
|
||||
{
|
||||
// GB Pocket
|
||||
gb.setDmgPaletteColor(0, 0, 13487791);
|
||||
gb.setDmgPaletteColor(0, 1, 10987158);
|
||||
gb.setDmgPaletteColor(0, 2, 6974033);
|
||||
gb.setDmgPaletteColor(0, 3, 2828823);
|
||||
gb.setDmgPaletteColor(1, 0, 13487791);
|
||||
gb.setDmgPaletteColor(1, 1, 10987158);
|
||||
gb.setDmgPaletteColor(1, 2, 6974033);
|
||||
gb.setDmgPaletteColor(1, 3, 2828823);
|
||||
gb.setDmgPaletteColor(2, 0, 13487791);
|
||||
gb.setDmgPaletteColor(2, 1, 10987158);
|
||||
gb.setDmgPaletteColor(2, 2, 6974033);
|
||||
gb.setDmgPaletteColor(2, 3, 2828823);
|
||||
|
||||
// gb.setDmgPaletteColor(0, 0, 13029285);
|
||||
// gb.setDmgPaletteColor(0, 1, 9213547);
|
||||
// gb.setDmgPaletteColor(0, 2, 4870457);
|
||||
// gb.setDmgPaletteColor(0, 3, 1580056);
|
||||
// gb.setDmgPaletteColor(1, 0, 13029285);
|
||||
// gb.setDmgPaletteColor(1, 1, 9213547);
|
||||
// gb.setDmgPaletteColor(1, 2, 4870457);
|
||||
// gb.setDmgPaletteColor(1, 3, 1580056);
|
||||
// gb.setDmgPaletteColor(2, 0, 13029285);
|
||||
// gb.setDmgPaletteColor(2, 1, 9213547);
|
||||
// gb.setDmgPaletteColor(2, 2, 4870457);
|
||||
// gb.setDmgPaletteColor(2, 3, 1580056);
|
||||
return;
|
||||
}
|
||||
else
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal(palette.UTF8String));
|
||||
|
||||
unsigned long rgb32 = 0;
|
||||
for (unsigned palnum = 0; palnum < 3; ++palnum)
|
||||
{
|
||||
for (unsigned colornum = 0; colornum < 4; ++colornum)
|
||||
{
|
||||
rgb32 = gbcToRgb32(gbc_bios_palette[palnum * 4 + colornum]);
|
||||
gb.setDmgPaletteColor(palnum, colornum, rgb32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+351
-435
@@ -35,50 +35,47 @@
|
||||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
828387BA0E6CDB6500A96E2C /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = B5F6D8AC0E66921B001CA5D3 /* Credits.rtf */; };
|
||||
828387BB0E6CDB6500A96E2C /* gameboy.icns in Resources */ = {isa = PBXBuildFile; fileRef = B5F6D8A80E66914F001CA5D3 /* gameboy.icns */; };
|
||||
828387BD0E6CDB6500A96E2C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165FFE840EACC02AAC07 /* InfoPlist.strings */; };
|
||||
828387E20E6CDB6E00A96E2C /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */; };
|
||||
82F45FC50E88979600B7B023 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 82F45FC40E88979600B7B023 /* Preferences.xib */; };
|
||||
94ABD6E9165340E500035061 /* chainresampler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD6BC165340E500035061 /* chainresampler.cpp */; };
|
||||
94ABD6EA165340E500035061 /* i0.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD6C3165340E500035061 /* i0.cpp */; };
|
||||
94ABD6EB165340E500035061 /* makesinckernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD6C8165340E500035061 /* makesinckernel.cpp */; };
|
||||
94ABD6EC165340E500035061 /* resamplerinfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD6CB165340E500035061 /* resamplerinfo.cpp */; };
|
||||
94ABD6ED165340E500035061 /* u48div.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD6CE165340E500035061 /* u48div.cpp */; };
|
||||
94ABD7BB1653428B00035061 /* bitmap_font.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD76F1653428B00035061 /* bitmap_font.cpp */; };
|
||||
94ABD7BC1653428B00035061 /* cpu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7721653428B00035061 /* cpu.cpp */; };
|
||||
94ABD7BD1653428B00035061 /* file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7751653428B00035061 /* file.cpp */; };
|
||||
94ABD7C11653428B00035061 /* gambatte.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD77F1653428B00035061 /* gambatte.cpp */; };
|
||||
94ABD7C21653428B00035061 /* initstate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7801653428B00035061 /* initstate.cpp */; };
|
||||
94ABD7C31653428B00035061 /* interrupter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7831653428B00035061 /* interrupter.cpp */; };
|
||||
94ABD7C41653428B00035061 /* interruptrequester.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7851653428B00035061 /* interruptrequester.cpp */; };
|
||||
94ABD7C51653428B00035061 /* cartridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7881653428B00035061 /* cartridge.cpp */; };
|
||||
94ABD7C61653428B00035061 /* memptrs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD78A1653428B00035061 /* memptrs.cpp */; };
|
||||
94ABD7C71653428B00035061 /* rtc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD78C1653428B00035061 /* rtc.cpp */; };
|
||||
94ABD7C81653428B00035061 /* memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD78E1653428B00035061 /* memory.cpp */; };
|
||||
94ABD7C91653428B00035061 /* channel1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7941653428B00035061 /* channel1.cpp */; };
|
||||
94ABD7CA1653428B00035061 /* channel2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7961653428B00035061 /* channel2.cpp */; };
|
||||
94ABD7CB1653428B00035061 /* channel3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7981653428B00035061 /* channel3.cpp */; };
|
||||
94ABD7CC1653428B00035061 /* channel4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD79A1653428B00035061 /* channel4.cpp */; };
|
||||
94ABD7CD1653428B00035061 /* duty_unit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD79C1653428B00035061 /* duty_unit.cpp */; };
|
||||
94ABD7CE1653428B00035061 /* envelope_unit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD79E1653428B00035061 /* envelope_unit.cpp */; };
|
||||
94ABD7CF1653428B00035061 /* length_counter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7A01653428B00035061 /* length_counter.cpp */; };
|
||||
94ABD7D01653428B00035061 /* sound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7A51653428B00035061 /* sound.cpp */; };
|
||||
94ABD7D11653428B00035061 /* state_osd_elements.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7A71653428B00035061 /* state_osd_elements.cpp */; };
|
||||
94ABD7D21653428B00035061 /* statesaver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7A91653428B00035061 /* statesaver.cpp */; };
|
||||
94ABD7D31653428B00035061 /* tima.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7AB1653428B00035061 /* tima.cpp */; };
|
||||
94ABD7D41653428B00035061 /* ly_counter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7AE1653428B00035061 /* ly_counter.cpp */; };
|
||||
94ABD7D51653428B00035061 /* lyc_irq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7B01653428B00035061 /* lyc_irq.cpp */; };
|
||||
94ABD7D61653428B00035061 /* next_m0_time.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7B21653428B00035061 /* next_m0_time.cpp */; };
|
||||
94ABD7D71653428B00035061 /* ppu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7B41653428B00035061 /* ppu.cpp */; };
|
||||
94ABD7D81653428B00035061 /* sprite_mapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7B61653428B00035061 /* sprite_mapper.cpp */; };
|
||||
94ABD7D91653428B00035061 /* video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7B81653428B00035061 /* video.cpp */; };
|
||||
8F14C4F929FF7217000D080B /* statesaver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F14C4F829FF7217000D080B /* statesaver.cpp */; };
|
||||
9499B5D81AB242B200276D21 /* chainresampler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B54E1AB242B200276D21 /* chainresampler.cpp */; };
|
||||
9499B5D91AB242B200276D21 /* i0.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5541AB242B200276D21 /* i0.cpp */; };
|
||||
9499B5DA1AB242B200276D21 /* kaiser50sinc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5561AB242B200276D21 /* kaiser50sinc.cpp */; };
|
||||
9499B5DB1AB242B200276D21 /* kaiser70sinc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5581AB242B200276D21 /* kaiser70sinc.cpp */; };
|
||||
9499B5DC1AB242B200276D21 /* makesinckernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B55B1AB242B200276D21 /* makesinckernel.cpp */; };
|
||||
9499B5DD1AB242B200276D21 /* resamplerinfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B55F1AB242B200276D21 /* resamplerinfo.cpp */; };
|
||||
9499B5DE1AB242B200276D21 /* u48div.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5621AB242B200276D21 /* u48div.cpp */; };
|
||||
9499B5E81AB242B300276D21 /* bitmap_font.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5861AB242B200276D21 /* bitmap_font.cpp */; };
|
||||
9499B5E91AB242B300276D21 /* cpu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5891AB242B200276D21 /* cpu.cpp */; };
|
||||
9499B5EA1AB242B300276D21 /* file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B58C1AB242B200276D21 /* file.cpp */; };
|
||||
9499B5EE1AB242B300276D21 /* gambatte.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5961AB242B200276D21 /* gambatte.cpp */; };
|
||||
9499B5EF1AB242B300276D21 /* initstate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5971AB242B200276D21 /* initstate.cpp */; };
|
||||
9499B5F01AB242B300276D21 /* interrupter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B59A1AB242B200276D21 /* interrupter.cpp */; };
|
||||
9499B5F11AB242B300276D21 /* interruptrequester.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B59C1AB242B200276D21 /* interruptrequester.cpp */; };
|
||||
9499B5F21AB242B300276D21 /* loadres.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B59E1AB242B200276D21 /* loadres.cpp */; };
|
||||
9499B5F31AB242B300276D21 /* cartridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5A01AB242B200276D21 /* cartridge.cpp */; };
|
||||
9499B5F41AB242B300276D21 /* memptrs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5A21AB242B200276D21 /* memptrs.cpp */; };
|
||||
9499B5F51AB242B300276D21 /* pakinfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5A41AB242B200276D21 /* pakinfo.cpp */; };
|
||||
9499B5F61AB242B300276D21 /* rtc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5A61AB242B200276D21 /* rtc.cpp */; };
|
||||
9499B5F71AB242B300276D21 /* memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5A81AB242B200276D21 /* memory.cpp */; };
|
||||
9499B5F81AB242B300276D21 /* channel1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5AE1AB242B200276D21 /* channel1.cpp */; };
|
||||
9499B5F91AB242B300276D21 /* channel2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5B01AB242B200276D21 /* channel2.cpp */; };
|
||||
9499B5FA1AB242B300276D21 /* channel3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5B21AB242B200276D21 /* channel3.cpp */; };
|
||||
9499B5FB1AB242B300276D21 /* channel4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5B41AB242B200276D21 /* channel4.cpp */; };
|
||||
9499B5FC1AB242B300276D21 /* duty_unit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5B61AB242B200276D21 /* duty_unit.cpp */; };
|
||||
9499B5FD1AB242B300276D21 /* envelope_unit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5B81AB242B200276D21 /* envelope_unit.cpp */; };
|
||||
9499B5FE1AB242B300276D21 /* length_counter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5BA1AB242B200276D21 /* length_counter.cpp */; };
|
||||
9499B5FF1AB242B300276D21 /* sound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5BF1AB242B200276D21 /* sound.cpp */; };
|
||||
9499B6001AB242B300276D21 /* state_osd_elements.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5C11AB242B200276D21 /* state_osd_elements.cpp */; };
|
||||
9499B6021AB242B300276D21 /* tima.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5C51AB242B200276D21 /* tima.cpp */; };
|
||||
9499B6031AB242B300276D21 /* ly_counter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5C91AB242B200276D21 /* ly_counter.cpp */; };
|
||||
9499B6041AB242B300276D21 /* lyc_irq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5CB1AB242B200276D21 /* lyc_irq.cpp */; };
|
||||
9499B6051AB242B300276D21 /* next_m0_time.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5CE1AB242B200276D21 /* next_m0_time.cpp */; };
|
||||
9499B6061AB242B300276D21 /* ppu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5D01AB242B200276D21 /* ppu.cpp */; };
|
||||
9499B6071AB242B300276D21 /* sprite_mapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5D21AB242B200276D21 /* sprite_mapper.cpp */; };
|
||||
9499B6081AB242B300276D21 /* video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5D41AB242B200276D21 /* video.cpp */; };
|
||||
94ABD7DA16534BE800035061 /* GBGameCore.mm in Sources */ = {isa = PBXBuildFile; fileRef = B5EC4D420E6312DF0046BD93 /* GBGameCore.mm */; };
|
||||
94ABD7DD16534C8300035061 /* libretro.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94ABD7DB16534C8300035061 /* libretro.cpp */; };
|
||||
94F2867816C3832E0075A73E /* kaiser50sinc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94F2867616C3832E0075A73E /* kaiser50sinc.cpp */; };
|
||||
94F2867916C3832E0075A73E /* kaiser70sinc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94F2867716C3832E0075A73E /* kaiser70sinc.cpp */; };
|
||||
94F2867D16C383E20075A73E /* loadres.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94F2867C16C383E20075A73E /* loadres.cpp */; };
|
||||
94F2868016C3840F0075A73E /* pakinfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94F2867F16C3840F0075A73E /* pakinfo.cpp */; };
|
||||
C6D120EE1711308C00E868A8 /* OpenEmuBase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C6D120ED1711308C00E868A8 /* OpenEmuBase.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@@ -112,152 +109,121 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
089C1660FE840EACC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
|
||||
089C1660FE840EACC02AAC07 /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||
828387810E6CDB2200A96E2C /* Gambatte.oecoreplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Gambatte.oecoreplugin; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
828387820E6CDB2200A96E2C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
82F45FC40E88979600B7B023 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = Preferences.xib; sourceTree = "<group>"; };
|
||||
942597C7151470210074E3A3 /* OpenEmuBase.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenEmuBase.framework; path = ../OpenEmu/build/Release/OpenEmuBase.framework; sourceTree = "<group>"; };
|
||||
94ABD6B2165340E500035061 /* adaptivesleep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = adaptivesleep.cpp; sourceTree = "<group>"; };
|
||||
94ABD6B3165340E500035061 /* adaptivesleep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = adaptivesleep.h; sourceTree = "<group>"; };
|
||||
94ABD6B4165340E500035061 /* array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = array.h; sourceTree = "<group>"; };
|
||||
94ABD6B5165340E500035061 /* rateest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rateest.cpp; sourceTree = "<group>"; };
|
||||
94ABD6B6165340E500035061 /* rateest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rateest.h; sourceTree = "<group>"; };
|
||||
94ABD6B8165340E500035061 /* resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resampler.h; sourceTree = "<group>"; };
|
||||
94ABD6B9165340E500035061 /* resamplerinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resamplerinfo.h; sourceTree = "<group>"; };
|
||||
94ABD6BB165340E500035061 /* blackmansinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blackmansinc.h; sourceTree = "<group>"; };
|
||||
94ABD6BC165340E500035061 /* chainresampler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = chainresampler.cpp; sourceTree = "<group>"; };
|
||||
94ABD6BD165340E500035061 /* chainresampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chainresampler.h; sourceTree = "<group>"; };
|
||||
94ABD6BE165340E500035061 /* cic2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cic2.h; sourceTree = "<group>"; };
|
||||
94ABD6BF165340E500035061 /* cic3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cic3.h; sourceTree = "<group>"; };
|
||||
94ABD6C0165340E500035061 /* cic4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cic4.h; sourceTree = "<group>"; };
|
||||
94ABD6C1165340E500035061 /* convoluter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = convoluter.h; sourceTree = "<group>"; };
|
||||
94ABD6C2165340E500035061 /* hammingsinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hammingsinc.h; sourceTree = "<group>"; };
|
||||
94ABD6C3165340E500035061 /* i0.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = i0.cpp; sourceTree = "<group>"; };
|
||||
94ABD6C4165340E500035061 /* i0.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = i0.h; sourceTree = "<group>"; };
|
||||
94ABD6C5165340E500035061 /* kaiser50sinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kaiser50sinc.h; sourceTree = "<group>"; };
|
||||
94ABD6C6165340E500035061 /* kaiser70sinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kaiser70sinc.h; sourceTree = "<group>"; };
|
||||
94ABD6C7165340E500035061 /* linint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linint.h; sourceTree = "<group>"; };
|
||||
94ABD6C8165340E500035061 /* makesinckernel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = makesinckernel.cpp; sourceTree = "<group>"; };
|
||||
94ABD6C9165340E500035061 /* makesinckernel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = makesinckernel.h; sourceTree = "<group>"; };
|
||||
94ABD6CA165340E500035061 /* rectsinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rectsinc.h; sourceTree = "<group>"; };
|
||||
94ABD6CB165340E500035061 /* resamplerinfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = resamplerinfo.cpp; sourceTree = "<group>"; };
|
||||
94ABD6CC165340E500035061 /* rshift16_round.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rshift16_round.h; sourceTree = "<group>"; };
|
||||
94ABD6CD165340E500035061 /* subresampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = subresampler.h; sourceTree = "<group>"; };
|
||||
94ABD6CE165340E500035061 /* u48div.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = u48div.cpp; sourceTree = "<group>"; };
|
||||
94ABD6CF165340E500035061 /* u48div.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = u48div.h; sourceTree = "<group>"; };
|
||||
94ABD6D0165340E500035061 /* upsampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = upsampler.h; sourceTree = "<group>"; };
|
||||
94ABD6D1165340E500035061 /* ringbuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ringbuffer.h; sourceTree = "<group>"; };
|
||||
94ABD6D2165340E500035061 /* skipsched.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = skipsched.cpp; sourceTree = "<group>"; };
|
||||
94ABD6D3165340E500035061 /* skipsched.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = skipsched.h; sourceTree = "<group>"; };
|
||||
94ABD6D4165340E500035061 /* uncopyable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uncopyable.h; sourceTree = "<group>"; };
|
||||
94ABD6D5165340E500035061 /* usec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usec.h; sourceTree = "<group>"; };
|
||||
94ABD6D7165340E500035061 /* rgb32conv.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rgb32conv.cpp; sourceTree = "<group>"; };
|
||||
94ABD6D8165340E500035061 /* rgb32conv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rgb32conv.h; sourceTree = "<group>"; };
|
||||
94ABD6D9165340E500035061 /* vfilterinfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vfilterinfo.cpp; sourceTree = "<group>"; };
|
||||
94ABD6DA165340E500035061 /* vfilterinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vfilterinfo.h; sourceTree = "<group>"; };
|
||||
94ABD6DC165340E500035061 /* catrom2x.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = catrom2x.cpp; sourceTree = "<group>"; };
|
||||
94ABD6DD165340E500035061 /* catrom2x.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catrom2x.h; sourceTree = "<group>"; };
|
||||
94ABD6DE165340E500035061 /* catrom3x.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = catrom3x.cpp; sourceTree = "<group>"; };
|
||||
94ABD6DF165340E500035061 /* catrom3x.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catrom3x.h; sourceTree = "<group>"; };
|
||||
94ABD6E0165340E500035061 /* kreed2xsai.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = kreed2xsai.cpp; sourceTree = "<group>"; };
|
||||
94ABD6E1165340E500035061 /* kreed2xsai.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kreed2xsai.h; sourceTree = "<group>"; };
|
||||
94ABD6E2165340E500035061 /* maxsthq2x.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = maxsthq2x.cpp; sourceTree = "<group>"; };
|
||||
94ABD6E3165340E500035061 /* maxsthq2x.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = maxsthq2x.h; sourceTree = "<group>"; };
|
||||
94ABD6E4165340E500035061 /* maxsthq3x.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = maxsthq3x.cpp; sourceTree = "<group>"; };
|
||||
94ABD6E5165340E500035061 /* maxsthq3x.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = maxsthq3x.h; sourceTree = "<group>"; };
|
||||
94ABD6E6165340E500035061 /* videolink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = videolink.h; sourceTree = "<group>"; };
|
||||
94ABD76A1653428B00035061 /* gambatte.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gambatte.h; sourceTree = "<group>"; };
|
||||
94ABD76B1653428B00035061 /* gbint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gbint.h; sourceTree = "<group>"; };
|
||||
94ABD76C1653428B00035061 /* inputgetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inputgetter.h; sourceTree = "<group>"; };
|
||||
94ABD76D1653428B00035061 /* SConstruct */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SConstruct; sourceTree = "<group>"; };
|
||||
94ABD76F1653428B00035061 /* bitmap_font.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bitmap_font.cpp; sourceTree = "<group>"; };
|
||||
94ABD7701653428B00035061 /* bitmap_font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bitmap_font.h; sourceTree = "<group>"; };
|
||||
94ABD7711653428B00035061 /* counterdef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = counterdef.h; sourceTree = "<group>"; };
|
||||
94ABD7721653428B00035061 /* cpu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cpu.cpp; sourceTree = "<group>"; };
|
||||
94ABD7731653428B00035061 /* cpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cpu.h; sourceTree = "<group>"; };
|
||||
94ABD7751653428B00035061 /* file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file.cpp; sourceTree = "<group>"; };
|
||||
94ABD7761653428B00035061 /* file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file.h; sourceTree = "<group>"; };
|
||||
94ABD7771653428B00035061 /* file_zip.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_zip.cpp; sourceTree = "<group>"; };
|
||||
94ABD7781653428B00035061 /* stdfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stdfile.h; sourceTree = "<group>"; };
|
||||
94ABD77A1653428B00035061 /* crypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypt.h; sourceTree = "<group>"; };
|
||||
94ABD77B1653428B00035061 /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapi.c; sourceTree = "<group>"; };
|
||||
94ABD77C1653428B00035061 /* ioapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ioapi.h; sourceTree = "<group>"; };
|
||||
94ABD77D1653428B00035061 /* unzip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = unzip.c; sourceTree = "<group>"; };
|
||||
94ABD77E1653428B00035061 /* unzip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unzip.h; sourceTree = "<group>"; };
|
||||
94ABD77F1653428B00035061 /* gambatte.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gambatte.cpp; sourceTree = "<group>"; };
|
||||
94ABD7801653428B00035061 /* initstate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = initstate.cpp; sourceTree = "<group>"; };
|
||||
94ABD7811653428B00035061 /* initstate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = initstate.h; sourceTree = "<group>"; };
|
||||
94ABD7821653428B00035061 /* insertion_sort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = insertion_sort.h; sourceTree = "<group>"; };
|
||||
94ABD7831653428B00035061 /* interrupter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = interrupter.cpp; sourceTree = "<group>"; };
|
||||
94ABD7841653428B00035061 /* interrupter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interrupter.h; sourceTree = "<group>"; };
|
||||
94ABD7851653428B00035061 /* interruptrequester.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = interruptrequester.cpp; sourceTree = "<group>"; };
|
||||
94ABD7861653428B00035061 /* interruptrequester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interruptrequester.h; sourceTree = "<group>"; };
|
||||
94ABD7881653428B00035061 /* cartridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cartridge.cpp; sourceTree = "<group>"; };
|
||||
94ABD7891653428B00035061 /* cartridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cartridge.h; sourceTree = "<group>"; };
|
||||
94ABD78A1653428B00035061 /* memptrs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = memptrs.cpp; sourceTree = "<group>"; };
|
||||
94ABD78B1653428B00035061 /* memptrs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memptrs.h; sourceTree = "<group>"; };
|
||||
94ABD78C1653428B00035061 /* rtc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rtc.cpp; sourceTree = "<group>"; };
|
||||
94ABD78D1653428B00035061 /* rtc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rtc.h; sourceTree = "<group>"; };
|
||||
94ABD78E1653428B00035061 /* memory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = memory.cpp; sourceTree = "<group>"; };
|
||||
94ABD78F1653428B00035061 /* memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory.h; sourceTree = "<group>"; };
|
||||
94ABD7901653428B00035061 /* minkeeper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = minkeeper.h; sourceTree = "<group>"; };
|
||||
94ABD7911653428B00035061 /* osd_element.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = osd_element.h; sourceTree = "<group>"; };
|
||||
94ABD7921653428B00035061 /* savestate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = savestate.h; sourceTree = "<group>"; };
|
||||
94ABD7941653428B00035061 /* channel1.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = channel1.cpp; sourceTree = "<group>"; };
|
||||
94ABD7951653428B00035061 /* channel1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = channel1.h; sourceTree = "<group>"; };
|
||||
94ABD7961653428B00035061 /* channel2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = channel2.cpp; sourceTree = "<group>"; };
|
||||
94ABD7971653428B00035061 /* channel2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = channel2.h; sourceTree = "<group>"; };
|
||||
94ABD7981653428B00035061 /* channel3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = channel3.cpp; sourceTree = "<group>"; };
|
||||
94ABD7991653428B00035061 /* channel3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = channel3.h; sourceTree = "<group>"; };
|
||||
94ABD79A1653428B00035061 /* channel4.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = channel4.cpp; sourceTree = "<group>"; };
|
||||
94ABD79B1653428B00035061 /* channel4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = channel4.h; sourceTree = "<group>"; };
|
||||
94ABD79C1653428B00035061 /* duty_unit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = duty_unit.cpp; sourceTree = "<group>"; };
|
||||
94ABD79D1653428B00035061 /* duty_unit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = duty_unit.h; sourceTree = "<group>"; };
|
||||
94ABD79E1653428B00035061 /* envelope_unit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = envelope_unit.cpp; sourceTree = "<group>"; };
|
||||
94ABD79F1653428B00035061 /* envelope_unit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = envelope_unit.h; sourceTree = "<group>"; };
|
||||
94ABD7A01653428B00035061 /* length_counter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = length_counter.cpp; sourceTree = "<group>"; };
|
||||
94ABD7A11653428B00035061 /* length_counter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = length_counter.h; sourceTree = "<group>"; };
|
||||
94ABD7A21653428B00035061 /* master_disabler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = master_disabler.h; sourceTree = "<group>"; };
|
||||
94ABD7A31653428B00035061 /* sound_unit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sound_unit.h; sourceTree = "<group>"; };
|
||||
94ABD7A41653428B00035061 /* static_output_tester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = static_output_tester.h; sourceTree = "<group>"; };
|
||||
94ABD7A51653428B00035061 /* sound.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sound.cpp; sourceTree = "<group>"; };
|
||||
94ABD7A61653428B00035061 /* sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sound.h; sourceTree = "<group>"; };
|
||||
94ABD7A71653428B00035061 /* state_osd_elements.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = state_osd_elements.cpp; sourceTree = "<group>"; };
|
||||
94ABD7A81653428B00035061 /* state_osd_elements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = state_osd_elements.h; sourceTree = "<group>"; };
|
||||
94ABD7A91653428B00035061 /* statesaver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = statesaver.cpp; sourceTree = "<group>"; };
|
||||
94ABD7AA1653428B00035061 /* statesaver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = statesaver.h; sourceTree = "<group>"; };
|
||||
94ABD7AB1653428B00035061 /* tima.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tima.cpp; sourceTree = "<group>"; };
|
||||
94ABD7AC1653428B00035061 /* tima.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tima.h; sourceTree = "<group>"; };
|
||||
94ABD7AE1653428B00035061 /* ly_counter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ly_counter.cpp; sourceTree = "<group>"; };
|
||||
94ABD7AF1653428B00035061 /* ly_counter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ly_counter.h; sourceTree = "<group>"; };
|
||||
94ABD7B01653428B00035061 /* lyc_irq.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lyc_irq.cpp; sourceTree = "<group>"; };
|
||||
94ABD7B11653428B00035061 /* lyc_irq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lyc_irq.h; sourceTree = "<group>"; };
|
||||
94ABD7B21653428B00035061 /* next_m0_time.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = next_m0_time.cpp; sourceTree = "<group>"; };
|
||||
94ABD7B31653428B00035061 /* next_m0_time.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = next_m0_time.h; sourceTree = "<group>"; };
|
||||
94ABD7B41653428B00035061 /* ppu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ppu.cpp; sourceTree = "<group>"; };
|
||||
94ABD7B51653428B00035061 /* ppu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ppu.h; sourceTree = "<group>"; };
|
||||
94ABD7B61653428B00035061 /* sprite_mapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sprite_mapper.cpp; sourceTree = "<group>"; };
|
||||
94ABD7B71653428B00035061 /* sprite_mapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sprite_mapper.h; sourceTree = "<group>"; };
|
||||
94ABD7B81653428B00035061 /* video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = video.cpp; sourceTree = "<group>"; };
|
||||
94ABD7B91653428B00035061 /* video.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = video.h; sourceTree = "<group>"; };
|
||||
94ABD7DB16534C8300035061 /* libretro.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = libretro.cpp; sourceTree = "<group>"; };
|
||||
94ABD7DC16534C8300035061 /* libretro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libretro.h; sourceTree = "<group>"; };
|
||||
94F0DAA916FE2FD5001ECA15 /* gbcpalettes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gbcpalettes.h; sourceTree = "<group>"; };
|
||||
94F2867616C3832E0075A73E /* kaiser50sinc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = kaiser50sinc.cpp; sourceTree = "<group>"; };
|
||||
94F2867716C3832E0075A73E /* kaiser70sinc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = kaiser70sinc.cpp; sourceTree = "<group>"; };
|
||||
94F2867A16C3836B0075A73E /* loadres.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loadres.h; sourceTree = "<group>"; };
|
||||
94F2867B16C3836B0075A73E /* pakinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pakinfo.h; sourceTree = "<group>"; };
|
||||
94F2867C16C383E20075A73E /* loadres.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loadres.cpp; sourceTree = "<group>"; };
|
||||
94F2867E16C3840F0075A73E /* pakinfo_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pakinfo_internal.h; sourceTree = "<group>"; };
|
||||
94F2867F16C3840F0075A73E /* pakinfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pakinfo.cpp; sourceTree = "<group>"; };
|
||||
B50BBE0F0E64825D001814C0 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = /System/Library/Frameworks/AudioToolbox.framework; sourceTree = "<absolute>"; };
|
||||
B5350B7C0E62EC0800A0903A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
|
||||
8F14C4F729FF7204000D080B /* memfile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = memfile.h; sourceTree = "<group>"; };
|
||||
8F14C4F829FF7217000D080B /* statesaver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = statesaver.cpp; sourceTree = "<group>"; };
|
||||
9499B5451AB242B200276D21 /* array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = array.h; sourceTree = "<group>"; };
|
||||
9499B5461AB242B200276D21 /* defined_ptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = defined_ptr.h; sourceTree = "<group>"; };
|
||||
9499B54A1AB242B200276D21 /* resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resampler.h; sourceTree = "<group>"; };
|
||||
9499B54B1AB242B200276D21 /* resamplerinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resamplerinfo.h; sourceTree = "<group>"; };
|
||||
9499B54D1AB242B200276D21 /* blackmansinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blackmansinc.h; sourceTree = "<group>"; };
|
||||
9499B54E1AB242B200276D21 /* chainresampler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = chainresampler.cpp; sourceTree = "<group>"; };
|
||||
9499B54F1AB242B200276D21 /* chainresampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chainresampler.h; sourceTree = "<group>"; };
|
||||
9499B5501AB242B200276D21 /* cic2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cic2.h; sourceTree = "<group>"; };
|
||||
9499B5511AB242B200276D21 /* cic3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cic3.h; sourceTree = "<group>"; };
|
||||
9499B5521AB242B200276D21 /* cic4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cic4.h; sourceTree = "<group>"; };
|
||||
9499B5531AB242B200276D21 /* hammingsinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hammingsinc.h; sourceTree = "<group>"; };
|
||||
9499B5541AB242B200276D21 /* i0.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = i0.cpp; sourceTree = "<group>"; };
|
||||
9499B5551AB242B200276D21 /* i0.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = i0.h; sourceTree = "<group>"; };
|
||||
9499B5561AB242B200276D21 /* kaiser50sinc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = kaiser50sinc.cpp; sourceTree = "<group>"; };
|
||||
9499B5571AB242B200276D21 /* kaiser50sinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kaiser50sinc.h; sourceTree = "<group>"; };
|
||||
9499B5581AB242B200276D21 /* kaiser70sinc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = kaiser70sinc.cpp; sourceTree = "<group>"; };
|
||||
9499B5591AB242B200276D21 /* kaiser70sinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kaiser70sinc.h; sourceTree = "<group>"; };
|
||||
9499B55A1AB242B200276D21 /* linint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linint.h; sourceTree = "<group>"; };
|
||||
9499B55B1AB242B200276D21 /* makesinckernel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = makesinckernel.cpp; sourceTree = "<group>"; };
|
||||
9499B55C1AB242B200276D21 /* makesinckernel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = makesinckernel.h; sourceTree = "<group>"; };
|
||||
9499B55D1AB242B200276D21 /* polyphasefir.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = polyphasefir.h; sourceTree = "<group>"; };
|
||||
9499B55E1AB242B200276D21 /* rectsinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rectsinc.h; sourceTree = "<group>"; };
|
||||
9499B55F1AB242B200276D21 /* resamplerinfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = resamplerinfo.cpp; sourceTree = "<group>"; };
|
||||
9499B5601AB242B200276D21 /* rshift16_round.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rshift16_round.h; sourceTree = "<group>"; };
|
||||
9499B5611AB242B200276D21 /* subresampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = subresampler.h; sourceTree = "<group>"; };
|
||||
9499B5621AB242B200276D21 /* u48div.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = u48div.cpp; sourceTree = "<group>"; };
|
||||
9499B5631AB242B200276D21 /* u48div.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = u48div.h; sourceTree = "<group>"; };
|
||||
9499B5641AB242B200276D21 /* upsampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = upsampler.h; sourceTree = "<group>"; };
|
||||
9499B5661AB242B200276D21 /* scoped_ptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scoped_ptr.h; sourceTree = "<group>"; };
|
||||
9499B5691AB242B200276D21 /* transfer_ptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = transfer_ptr.h; sourceTree = "<group>"; };
|
||||
9499B56A1AB242B200276D21 /* uncopyable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uncopyable.h; sourceTree = "<group>"; };
|
||||
9499B57F1AB242B200276D21 /* gambatte.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gambatte.h; sourceTree = "<group>"; };
|
||||
9499B5801AB242B200276D21 /* gbint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gbint.h; sourceTree = "<group>"; };
|
||||
9499B5811AB242B200276D21 /* inputgetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inputgetter.h; sourceTree = "<group>"; };
|
||||
9499B5821AB242B200276D21 /* loadres.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loadres.h; sourceTree = "<group>"; };
|
||||
9499B5831AB242B200276D21 /* pakinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pakinfo.h; sourceTree = "<group>"; };
|
||||
9499B5861AB242B200276D21 /* bitmap_font.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bitmap_font.cpp; sourceTree = "<group>"; };
|
||||
9499B5871AB242B200276D21 /* bitmap_font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bitmap_font.h; sourceTree = "<group>"; };
|
||||
9499B5881AB242B200276D21 /* counterdef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = counterdef.h; sourceTree = "<group>"; };
|
||||
9499B5891AB242B200276D21 /* cpu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cpu.cpp; sourceTree = "<group>"; };
|
||||
9499B58A1AB242B200276D21 /* cpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cpu.h; sourceTree = "<group>"; };
|
||||
9499B58C1AB242B200276D21 /* file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file.cpp; sourceTree = "<group>"; };
|
||||
9499B58D1AB242B200276D21 /* file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file.h; sourceTree = "<group>"; };
|
||||
9499B58F1AB242B200276D21 /* stdfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stdfile.h; sourceTree = "<group>"; };
|
||||
9499B5961AB242B200276D21 /* gambatte.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gambatte.cpp; sourceTree = "<group>"; };
|
||||
9499B5971AB242B200276D21 /* initstate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = initstate.cpp; sourceTree = "<group>"; };
|
||||
9499B5981AB242B200276D21 /* initstate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = initstate.h; sourceTree = "<group>"; };
|
||||
9499B5991AB242B200276D21 /* insertion_sort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = insertion_sort.h; sourceTree = "<group>"; };
|
||||
9499B59A1AB242B200276D21 /* interrupter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = interrupter.cpp; sourceTree = "<group>"; };
|
||||
9499B59B1AB242B200276D21 /* interrupter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interrupter.h; sourceTree = "<group>"; };
|
||||
9499B59C1AB242B200276D21 /* interruptrequester.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = interruptrequester.cpp; sourceTree = "<group>"; };
|
||||
9499B59D1AB242B200276D21 /* interruptrequester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interruptrequester.h; sourceTree = "<group>"; };
|
||||
9499B59E1AB242B200276D21 /* loadres.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loadres.cpp; sourceTree = "<group>"; };
|
||||
9499B5A01AB242B200276D21 /* cartridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cartridge.cpp; sourceTree = "<group>"; };
|
||||
9499B5A11AB242B200276D21 /* cartridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cartridge.h; sourceTree = "<group>"; };
|
||||
9499B5A21AB242B200276D21 /* memptrs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = memptrs.cpp; sourceTree = "<group>"; };
|
||||
9499B5A31AB242B200276D21 /* memptrs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memptrs.h; sourceTree = "<group>"; };
|
||||
9499B5A41AB242B200276D21 /* pakinfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pakinfo.cpp; sourceTree = "<group>"; };
|
||||
9499B5A51AB242B200276D21 /* pakinfo_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pakinfo_internal.h; sourceTree = "<group>"; };
|
||||
9499B5A61AB242B200276D21 /* rtc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rtc.cpp; sourceTree = "<group>"; };
|
||||
9499B5A71AB242B200276D21 /* rtc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rtc.h; sourceTree = "<group>"; };
|
||||
9499B5A81AB242B200276D21 /* memory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = memory.cpp; sourceTree = "<group>"; };
|
||||
9499B5A91AB242B200276D21 /* memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory.h; sourceTree = "<group>"; };
|
||||
9499B5AA1AB242B200276D21 /* minkeeper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = minkeeper.h; sourceTree = "<group>"; };
|
||||
9499B5AB1AB242B200276D21 /* osd_element.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = osd_element.h; sourceTree = "<group>"; };
|
||||
9499B5AC1AB242B200276D21 /* savestate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = savestate.h; sourceTree = "<group>"; };
|
||||
9499B5AE1AB242B200276D21 /* channel1.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = channel1.cpp; sourceTree = "<group>"; };
|
||||
9499B5AF1AB242B200276D21 /* channel1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = channel1.h; sourceTree = "<group>"; };
|
||||
9499B5B01AB242B200276D21 /* channel2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = channel2.cpp; sourceTree = "<group>"; };
|
||||
9499B5B11AB242B200276D21 /* channel2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = channel2.h; sourceTree = "<group>"; };
|
||||
9499B5B21AB242B200276D21 /* channel3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = channel3.cpp; sourceTree = "<group>"; };
|
||||
9499B5B31AB242B200276D21 /* channel3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = channel3.h; sourceTree = "<group>"; };
|
||||
9499B5B41AB242B200276D21 /* channel4.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = channel4.cpp; sourceTree = "<group>"; };
|
||||
9499B5B51AB242B200276D21 /* channel4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = channel4.h; sourceTree = "<group>"; };
|
||||
9499B5B61AB242B200276D21 /* duty_unit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = duty_unit.cpp; sourceTree = "<group>"; };
|
||||
9499B5B71AB242B200276D21 /* duty_unit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = duty_unit.h; sourceTree = "<group>"; };
|
||||
9499B5B81AB242B200276D21 /* envelope_unit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = envelope_unit.cpp; sourceTree = "<group>"; };
|
||||
9499B5B91AB242B200276D21 /* envelope_unit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = envelope_unit.h; sourceTree = "<group>"; };
|
||||
9499B5BA1AB242B200276D21 /* length_counter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = length_counter.cpp; sourceTree = "<group>"; };
|
||||
9499B5BB1AB242B200276D21 /* length_counter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = length_counter.h; sourceTree = "<group>"; };
|
||||
9499B5BC1AB242B200276D21 /* master_disabler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = master_disabler.h; sourceTree = "<group>"; };
|
||||
9499B5BD1AB242B200276D21 /* sound_unit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sound_unit.h; sourceTree = "<group>"; };
|
||||
9499B5BE1AB242B200276D21 /* static_output_tester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = static_output_tester.h; sourceTree = "<group>"; };
|
||||
9499B5BF1AB242B200276D21 /* sound.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sound.cpp; sourceTree = "<group>"; };
|
||||
9499B5C01AB242B200276D21 /* sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sound.h; sourceTree = "<group>"; };
|
||||
9499B5C11AB242B200276D21 /* state_osd_elements.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = state_osd_elements.cpp; sourceTree = "<group>"; };
|
||||
9499B5C21AB242B200276D21 /* state_osd_elements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = state_osd_elements.h; sourceTree = "<group>"; };
|
||||
9499B5C31AB242B200276D21 /* statesaver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = statesaver.cpp; sourceTree = "<group>"; };
|
||||
9499B5C41AB242B200276D21 /* statesaver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = statesaver.h; sourceTree = "<group>"; };
|
||||
9499B5C51AB242B200276D21 /* tima.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tima.cpp; sourceTree = "<group>"; };
|
||||
9499B5C61AB242B200276D21 /* tima.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tima.h; sourceTree = "<group>"; };
|
||||
9499B5C81AB242B200276D21 /* lcddef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lcddef.h; sourceTree = "<group>"; };
|
||||
9499B5C91AB242B200276D21 /* ly_counter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ly_counter.cpp; sourceTree = "<group>"; };
|
||||
9499B5CA1AB242B200276D21 /* ly_counter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ly_counter.h; sourceTree = "<group>"; };
|
||||
9499B5CB1AB242B200276D21 /* lyc_irq.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lyc_irq.cpp; sourceTree = "<group>"; };
|
||||
9499B5CC1AB242B200276D21 /* lyc_irq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lyc_irq.h; sourceTree = "<group>"; };
|
||||
9499B5CE1AB242B200276D21 /* next_m0_time.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = next_m0_time.cpp; sourceTree = "<group>"; };
|
||||
9499B5CF1AB242B200276D21 /* next_m0_time.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = next_m0_time.h; sourceTree = "<group>"; };
|
||||
9499B5D01AB242B200276D21 /* ppu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ppu.cpp; sourceTree = "<group>"; };
|
||||
9499B5D11AB242B200276D21 /* ppu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ppu.h; sourceTree = "<group>"; };
|
||||
9499B5D21AB242B200276D21 /* sprite_mapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sprite_mapper.cpp; sourceTree = "<group>"; };
|
||||
9499B5D31AB242B200276D21 /* sprite_mapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sprite_mapper.h; sourceTree = "<group>"; };
|
||||
9499B5D41AB242B200276D21 /* video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = video.cpp; sourceTree = "<group>"; };
|
||||
9499B5D51AB242B200276D21 /* video.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = video.h; sourceTree = "<group>"; };
|
||||
B5350B7C0E62EC0800A0903A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
|
||||
B5EC4D410E6312DF0046BD93 /* GBGameCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GBGameCore.h; sourceTree = "<group>"; };
|
||||
B5EC4D420E6312DF0046BD93 /* GBGameCore.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GBGameCore.mm; sourceTree = "<group>"; };
|
||||
B5F6D8A80E66914F001CA5D3 /* gameboy.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = gameboy.icns; sourceTree = "<group>"; };
|
||||
B5F6D8AD0E66921B001CA5D3 /* English */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = English; path = English.lproj/Credits.rtf; sourceTree = "<group>"; };
|
||||
C6B947DE1364FD0C00A425F0 /* OEGBSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OEGBSystemResponderClient.h; path = ../OpenEmu/GameBoy/OEGBSystemResponderClient.h; sourceTree = "<group>"; };
|
||||
C6B947DE1364FD0C00A425F0 /* OEGBSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OEGBSystemResponderClient.h; path = ../OpenEmu/SystemPlugins/GameBoy/OEGBSystemResponderClient.h; sourceTree = "<group>"; };
|
||||
C6D120ED1711308C00E868A8 /* OpenEmuBase.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OpenEmuBase.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -277,8 +243,6 @@
|
||||
1058C7A6FEA54F5311CA2CBB /* Linked Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
942597C7151470210074E3A3 /* OpenEmuBase.framework */,
|
||||
B50BBE0F0E64825D001814C0 /* AudioToolbox.framework */,
|
||||
B5350B7C0E62EC0800A0903A /* OpenGL.framework */,
|
||||
1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */,
|
||||
);
|
||||
@@ -312,6 +276,7 @@
|
||||
);
|
||||
name = Gambatte;
|
||||
sourceTree = "<group>";
|
||||
usesTabs = 0;
|
||||
};
|
||||
2A37F4ABFDCFA73011CA2CEA /* Classes */ = {
|
||||
isa = PBXGroup;
|
||||
@@ -319,6 +284,7 @@
|
||||
C6B947DE1364FD0C00A425F0 /* OEGBSystemResponderClient.h */,
|
||||
B5EC4D410E6312DF0046BD93 /* GBGameCore.h */,
|
||||
B5EC4D420E6312DF0046BD93 /* GBGameCore.mm */,
|
||||
8F14C4F829FF7217000D080B /* statesaver.cpp */,
|
||||
);
|
||||
name = Classes;
|
||||
sourceTree = "<group>";
|
||||
@@ -334,10 +300,8 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
828387820E6CDB2200A96E2C /* Info.plist */,
|
||||
B5F6D8AC0E66921B001CA5D3 /* Credits.rtf */,
|
||||
B5F6D8A80E66914F001CA5D3 /* gameboy.icns */,
|
||||
089C165FFE840EACC02AAC07 /* InfoPlist.strings */,
|
||||
82F45FC40E88979600B7B023 /* Preferences.xib */,
|
||||
);
|
||||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
@@ -352,237 +316,162 @@
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94ABD6B1165340E500035061 /* common */ = {
|
||||
9499B5421AB242B200276D21 /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94ABD6B2165340E500035061 /* adaptivesleep.cpp */,
|
||||
94ABD6B3165340E500035061 /* adaptivesleep.h */,
|
||||
94ABD6B4165340E500035061 /* array.h */,
|
||||
94ABD6B5165340E500035061 /* rateest.cpp */,
|
||||
94ABD6B6165340E500035061 /* rateest.h */,
|
||||
94ABD6B7165340E500035061 /* resample */,
|
||||
94ABD6D1165340E500035061 /* ringbuffer.h */,
|
||||
94ABD6D2165340E500035061 /* skipsched.cpp */,
|
||||
94ABD6D3165340E500035061 /* skipsched.h */,
|
||||
94ABD6D4165340E500035061 /* uncopyable.h */,
|
||||
94ABD6D5165340E500035061 /* usec.h */,
|
||||
94ABD6D6165340E500035061 /* videolink */,
|
||||
9499B5451AB242B200276D21 /* array.h */,
|
||||
9499B5461AB242B200276D21 /* defined_ptr.h */,
|
||||
9499B5851AB242B200276D21 /* libgambatte */,
|
||||
9499B5491AB242B200276D21 /* resample */,
|
||||
9499B5661AB242B200276D21 /* scoped_ptr.h */,
|
||||
9499B5691AB242B200276D21 /* transfer_ptr.h */,
|
||||
9499B56A1AB242B200276D21 /* uncopyable.h */,
|
||||
);
|
||||
path = common;
|
||||
path = src;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94ABD6B7165340E500035061 /* resample */ = {
|
||||
9499B5491AB242B200276D21 /* resample */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94ABD6B8165340E500035061 /* resampler.h */,
|
||||
94ABD6B9165340E500035061 /* resamplerinfo.h */,
|
||||
94ABD6BA165340E500035061 /* src */,
|
||||
9499B54A1AB242B200276D21 /* resampler.h */,
|
||||
9499B54B1AB242B200276D21 /* resamplerinfo.h */,
|
||||
9499B54D1AB242B200276D21 /* blackmansinc.h */,
|
||||
9499B54E1AB242B200276D21 /* chainresampler.cpp */,
|
||||
9499B54F1AB242B200276D21 /* chainresampler.h */,
|
||||
9499B5501AB242B200276D21 /* cic2.h */,
|
||||
9499B5511AB242B200276D21 /* cic3.h */,
|
||||
9499B5521AB242B200276D21 /* cic4.h */,
|
||||
9499B5531AB242B200276D21 /* hammingsinc.h */,
|
||||
9499B5541AB242B200276D21 /* i0.cpp */,
|
||||
9499B5551AB242B200276D21 /* i0.h */,
|
||||
9499B5561AB242B200276D21 /* kaiser50sinc.cpp */,
|
||||
9499B5571AB242B200276D21 /* kaiser50sinc.h */,
|
||||
9499B5581AB242B200276D21 /* kaiser70sinc.cpp */,
|
||||
9499B5591AB242B200276D21 /* kaiser70sinc.h */,
|
||||
9499B55A1AB242B200276D21 /* linint.h */,
|
||||
9499B55B1AB242B200276D21 /* makesinckernel.cpp */,
|
||||
9499B55C1AB242B200276D21 /* makesinckernel.h */,
|
||||
9499B55D1AB242B200276D21 /* polyphasefir.h */,
|
||||
9499B55E1AB242B200276D21 /* rectsinc.h */,
|
||||
9499B55F1AB242B200276D21 /* resamplerinfo.cpp */,
|
||||
9499B5601AB242B200276D21 /* rshift16_round.h */,
|
||||
9499B5611AB242B200276D21 /* subresampler.h */,
|
||||
9499B5621AB242B200276D21 /* u48div.cpp */,
|
||||
9499B5631AB242B200276D21 /* u48div.h */,
|
||||
9499B5641AB242B200276D21 /* upsampler.h */,
|
||||
);
|
||||
path = resample;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94ABD6BA165340E500035061 /* src */ = {
|
||||
9499B5851AB242B200276D21 /* libgambatte */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94ABD6BB165340E500035061 /* blackmansinc.h */,
|
||||
94ABD6BC165340E500035061 /* chainresampler.cpp */,
|
||||
94ABD6BD165340E500035061 /* chainresampler.h */,
|
||||
94ABD6BE165340E500035061 /* cic2.h */,
|
||||
94ABD6BF165340E500035061 /* cic3.h */,
|
||||
94ABD6C0165340E500035061 /* cic4.h */,
|
||||
94ABD6C1165340E500035061 /* convoluter.h */,
|
||||
94ABD6C2165340E500035061 /* hammingsinc.h */,
|
||||
94ABD6C3165340E500035061 /* i0.cpp */,
|
||||
94ABD6C4165340E500035061 /* i0.h */,
|
||||
94ABD6C5165340E500035061 /* kaiser50sinc.h */,
|
||||
94ABD6C6165340E500035061 /* kaiser70sinc.h */,
|
||||
94F2867616C3832E0075A73E /* kaiser50sinc.cpp */,
|
||||
94F2867716C3832E0075A73E /* kaiser70sinc.cpp */,
|
||||
94ABD6C7165340E500035061 /* linint.h */,
|
||||
94ABD6C8165340E500035061 /* makesinckernel.cpp */,
|
||||
94ABD6C9165340E500035061 /* makesinckernel.h */,
|
||||
94ABD6CA165340E500035061 /* rectsinc.h */,
|
||||
94ABD6CB165340E500035061 /* resamplerinfo.cpp */,
|
||||
94ABD6CC165340E500035061 /* rshift16_round.h */,
|
||||
94ABD6CD165340E500035061 /* subresampler.h */,
|
||||
94ABD6CE165340E500035061 /* u48div.cpp */,
|
||||
94ABD6CF165340E500035061 /* u48div.h */,
|
||||
94ABD6D0165340E500035061 /* upsampler.h */,
|
||||
);
|
||||
path = src;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94ABD6D6165340E500035061 /* videolink */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94ABD6D7165340E500035061 /* rgb32conv.cpp */,
|
||||
94ABD6D8165340E500035061 /* rgb32conv.h */,
|
||||
94ABD6D9165340E500035061 /* vfilterinfo.cpp */,
|
||||
94ABD6DA165340E500035061 /* vfilterinfo.h */,
|
||||
94ABD6DB165340E500035061 /* vfilters */,
|
||||
94ABD6E6165340E500035061 /* videolink.h */,
|
||||
);
|
||||
path = videolink;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94ABD6DB165340E500035061 /* vfilters */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94ABD6DC165340E500035061 /* catrom2x.cpp */,
|
||||
94ABD6DD165340E500035061 /* catrom2x.h */,
|
||||
94ABD6DE165340E500035061 /* catrom3x.cpp */,
|
||||
94ABD6DF165340E500035061 /* catrom3x.h */,
|
||||
94ABD6E0165340E500035061 /* kreed2xsai.cpp */,
|
||||
94ABD6E1165340E500035061 /* kreed2xsai.h */,
|
||||
94ABD6E2165340E500035061 /* maxsthq2x.cpp */,
|
||||
94ABD6E3165340E500035061 /* maxsthq2x.h */,
|
||||
94ABD6E4165340E500035061 /* maxsthq3x.cpp */,
|
||||
94ABD6E5165340E500035061 /* maxsthq3x.h */,
|
||||
);
|
||||
path = vfilters;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94ABD7681653428B00035061 /* libgambatte */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94F0DAA916FE2FD5001ECA15 /* gbcpalettes.h */,
|
||||
94ABD7DB16534C8300035061 /* libretro.cpp */,
|
||||
94ABD7DC16534C8300035061 /* libretro.h */,
|
||||
94ABD7691653428B00035061 /* include */,
|
||||
94ABD76D1653428B00035061 /* SConstruct */,
|
||||
94ABD76E1653428B00035061 /* src */,
|
||||
9499B5861AB242B200276D21 /* bitmap_font.cpp */,
|
||||
9499B5871AB242B200276D21 /* bitmap_font.h */,
|
||||
9499B5881AB242B200276D21 /* counterdef.h */,
|
||||
9499B5891AB242B200276D21 /* cpu.cpp */,
|
||||
9499B58A1AB242B200276D21 /* cpu.h */,
|
||||
9499B58B1AB242B200276D21 /* file */,
|
||||
9499B5961AB242B200276D21 /* gambatte.cpp */,
|
||||
9499B57F1AB242B200276D21 /* gambatte.h */,
|
||||
9499B5801AB242B200276D21 /* gbint.h */,
|
||||
9499B5971AB242B200276D21 /* initstate.cpp */,
|
||||
9499B5981AB242B200276D21 /* initstate.h */,
|
||||
9499B5811AB242B200276D21 /* inputgetter.h */,
|
||||
9499B5991AB242B200276D21 /* insertion_sort.h */,
|
||||
9499B59A1AB242B200276D21 /* interrupter.cpp */,
|
||||
9499B59B1AB242B200276D21 /* interrupter.h */,
|
||||
9499B59C1AB242B200276D21 /* interruptrequester.cpp */,
|
||||
9499B59D1AB242B200276D21 /* interruptrequester.h */,
|
||||
9499B59E1AB242B200276D21 /* loadres.cpp */,
|
||||
9499B5821AB242B200276D21 /* loadres.h */,
|
||||
9499B59F1AB242B200276D21 /* mem */,
|
||||
9499B5A81AB242B200276D21 /* memory.cpp */,
|
||||
9499B5A91AB242B200276D21 /* memory.h */,
|
||||
9499B5AA1AB242B200276D21 /* minkeeper.h */,
|
||||
9499B5AB1AB242B200276D21 /* osd_element.h */,
|
||||
9499B5831AB242B200276D21 /* pakinfo.h */,
|
||||
9499B5AC1AB242B200276D21 /* savestate.h */,
|
||||
9499B5AD1AB242B200276D21 /* sound */,
|
||||
9499B5BF1AB242B200276D21 /* sound.cpp */,
|
||||
9499B5C01AB242B200276D21 /* sound.h */,
|
||||
9499B5C11AB242B200276D21 /* state_osd_elements.cpp */,
|
||||
9499B5C21AB242B200276D21 /* state_osd_elements.h */,
|
||||
9499B5C31AB242B200276D21 /* statesaver.cpp */,
|
||||
9499B5C41AB242B200276D21 /* statesaver.h */,
|
||||
9499B5C51AB242B200276D21 /* tima.cpp */,
|
||||
9499B5C61AB242B200276D21 /* tima.h */,
|
||||
9499B5C71AB242B200276D21 /* video */,
|
||||
9499B5D41AB242B200276D21 /* video.cpp */,
|
||||
9499B5D51AB242B200276D21 /* video.h */,
|
||||
);
|
||||
path = libgambatte;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94ABD7691653428B00035061 /* include */ = {
|
||||
9499B58B1AB242B200276D21 /* file */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94ABD76A1653428B00035061 /* gambatte.h */,
|
||||
94ABD76B1653428B00035061 /* gbint.h */,
|
||||
94ABD76C1653428B00035061 /* inputgetter.h */,
|
||||
94F2867A16C3836B0075A73E /* loadres.h */,
|
||||
94F2867B16C3836B0075A73E /* pakinfo.h */,
|
||||
);
|
||||
path = include;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94ABD76E1653428B00035061 /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94ABD76F1653428B00035061 /* bitmap_font.cpp */,
|
||||
94ABD7701653428B00035061 /* bitmap_font.h */,
|
||||
94ABD7711653428B00035061 /* counterdef.h */,
|
||||
94ABD7721653428B00035061 /* cpu.cpp */,
|
||||
94ABD7731653428B00035061 /* cpu.h */,
|
||||
94ABD7741653428B00035061 /* file */,
|
||||
94ABD77F1653428B00035061 /* gambatte.cpp */,
|
||||
94ABD7801653428B00035061 /* initstate.cpp */,
|
||||
94ABD7811653428B00035061 /* initstate.h */,
|
||||
94ABD7821653428B00035061 /* insertion_sort.h */,
|
||||
94ABD7831653428B00035061 /* interrupter.cpp */,
|
||||
94ABD7841653428B00035061 /* interrupter.h */,
|
||||
94ABD7851653428B00035061 /* interruptrequester.cpp */,
|
||||
94ABD7861653428B00035061 /* interruptrequester.h */,
|
||||
94F2867C16C383E20075A73E /* loadres.cpp */,
|
||||
94ABD7871653428B00035061 /* mem */,
|
||||
94ABD78E1653428B00035061 /* memory.cpp */,
|
||||
94ABD78F1653428B00035061 /* memory.h */,
|
||||
94ABD7901653428B00035061 /* minkeeper.h */,
|
||||
94ABD7911653428B00035061 /* osd_element.h */,
|
||||
94ABD7921653428B00035061 /* savestate.h */,
|
||||
94ABD7931653428B00035061 /* sound */,
|
||||
94ABD7A51653428B00035061 /* sound.cpp */,
|
||||
94ABD7A61653428B00035061 /* sound.h */,
|
||||
94ABD7A71653428B00035061 /* state_osd_elements.cpp */,
|
||||
94ABD7A81653428B00035061 /* state_osd_elements.h */,
|
||||
94ABD7A91653428B00035061 /* statesaver.cpp */,
|
||||
94ABD7AA1653428B00035061 /* statesaver.h */,
|
||||
94ABD7AB1653428B00035061 /* tima.cpp */,
|
||||
94ABD7AC1653428B00035061 /* tima.h */,
|
||||
94ABD7AD1653428B00035061 /* video */,
|
||||
94ABD7B81653428B00035061 /* video.cpp */,
|
||||
94ABD7B91653428B00035061 /* video.h */,
|
||||
);
|
||||
path = src;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94ABD7741653428B00035061 /* file */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94ABD7751653428B00035061 /* file.cpp */,
|
||||
94ABD7761653428B00035061 /* file.h */,
|
||||
94ABD7771653428B00035061 /* file_zip.cpp */,
|
||||
94ABD7781653428B00035061 /* stdfile.h */,
|
||||
94ABD7791653428B00035061 /* unzip */,
|
||||
9499B58C1AB242B200276D21 /* file.cpp */,
|
||||
9499B58D1AB242B200276D21 /* file.h */,
|
||||
8F14C4F729FF7204000D080B /* memfile.h */,
|
||||
9499B58F1AB242B200276D21 /* stdfile.h */,
|
||||
);
|
||||
path = file;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94ABD7791653428B00035061 /* unzip */ = {
|
||||
9499B59F1AB242B200276D21 /* mem */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94ABD77A1653428B00035061 /* crypt.h */,
|
||||
94ABD77B1653428B00035061 /* ioapi.c */,
|
||||
94ABD77C1653428B00035061 /* ioapi.h */,
|
||||
94ABD77D1653428B00035061 /* unzip.c */,
|
||||
94ABD77E1653428B00035061 /* unzip.h */,
|
||||
);
|
||||
path = unzip;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94ABD7871653428B00035061 /* mem */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94ABD7881653428B00035061 /* cartridge.cpp */,
|
||||
94ABD7891653428B00035061 /* cartridge.h */,
|
||||
94ABD78A1653428B00035061 /* memptrs.cpp */,
|
||||
94ABD78B1653428B00035061 /* memptrs.h */,
|
||||
94F2867E16C3840F0075A73E /* pakinfo_internal.h */,
|
||||
94F2867F16C3840F0075A73E /* pakinfo.cpp */,
|
||||
94ABD78C1653428B00035061 /* rtc.cpp */,
|
||||
94ABD78D1653428B00035061 /* rtc.h */,
|
||||
9499B5A01AB242B200276D21 /* cartridge.cpp */,
|
||||
9499B5A11AB242B200276D21 /* cartridge.h */,
|
||||
9499B5A21AB242B200276D21 /* memptrs.cpp */,
|
||||
9499B5A31AB242B200276D21 /* memptrs.h */,
|
||||
9499B5A41AB242B200276D21 /* pakinfo.cpp */,
|
||||
9499B5A51AB242B200276D21 /* pakinfo_internal.h */,
|
||||
9499B5A61AB242B200276D21 /* rtc.cpp */,
|
||||
9499B5A71AB242B200276D21 /* rtc.h */,
|
||||
);
|
||||
path = mem;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94ABD7931653428B00035061 /* sound */ = {
|
||||
9499B5AD1AB242B200276D21 /* sound */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94ABD7941653428B00035061 /* channel1.cpp */,
|
||||
94ABD7951653428B00035061 /* channel1.h */,
|
||||
94ABD7961653428B00035061 /* channel2.cpp */,
|
||||
94ABD7971653428B00035061 /* channel2.h */,
|
||||
94ABD7981653428B00035061 /* channel3.cpp */,
|
||||
94ABD7991653428B00035061 /* channel3.h */,
|
||||
94ABD79A1653428B00035061 /* channel4.cpp */,
|
||||
94ABD79B1653428B00035061 /* channel4.h */,
|
||||
94ABD79C1653428B00035061 /* duty_unit.cpp */,
|
||||
94ABD79D1653428B00035061 /* duty_unit.h */,
|
||||
94ABD79E1653428B00035061 /* envelope_unit.cpp */,
|
||||
94ABD79F1653428B00035061 /* envelope_unit.h */,
|
||||
94ABD7A01653428B00035061 /* length_counter.cpp */,
|
||||
94ABD7A11653428B00035061 /* length_counter.h */,
|
||||
94ABD7A21653428B00035061 /* master_disabler.h */,
|
||||
94ABD7A31653428B00035061 /* sound_unit.h */,
|
||||
94ABD7A41653428B00035061 /* static_output_tester.h */,
|
||||
9499B5AE1AB242B200276D21 /* channel1.cpp */,
|
||||
9499B5AF1AB242B200276D21 /* channel1.h */,
|
||||
9499B5B01AB242B200276D21 /* channel2.cpp */,
|
||||
9499B5B11AB242B200276D21 /* channel2.h */,
|
||||
9499B5B21AB242B200276D21 /* channel3.cpp */,
|
||||
9499B5B31AB242B200276D21 /* channel3.h */,
|
||||
9499B5B41AB242B200276D21 /* channel4.cpp */,
|
||||
9499B5B51AB242B200276D21 /* channel4.h */,
|
||||
9499B5B61AB242B200276D21 /* duty_unit.cpp */,
|
||||
9499B5B71AB242B200276D21 /* duty_unit.h */,
|
||||
9499B5B81AB242B200276D21 /* envelope_unit.cpp */,
|
||||
9499B5B91AB242B200276D21 /* envelope_unit.h */,
|
||||
9499B5BA1AB242B200276D21 /* length_counter.cpp */,
|
||||
9499B5BB1AB242B200276D21 /* length_counter.h */,
|
||||
9499B5BC1AB242B200276D21 /* master_disabler.h */,
|
||||
9499B5BD1AB242B200276D21 /* sound_unit.h */,
|
||||
9499B5BE1AB242B200276D21 /* static_output_tester.h */,
|
||||
);
|
||||
path = sound;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
94ABD7AD1653428B00035061 /* video */ = {
|
||||
9499B5C71AB242B200276D21 /* video */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94ABD7AE1653428B00035061 /* ly_counter.cpp */,
|
||||
94ABD7AF1653428B00035061 /* ly_counter.h */,
|
||||
94ABD7B01653428B00035061 /* lyc_irq.cpp */,
|
||||
94ABD7B11653428B00035061 /* lyc_irq.h */,
|
||||
94ABD7B21653428B00035061 /* next_m0_time.cpp */,
|
||||
94ABD7B31653428B00035061 /* next_m0_time.h */,
|
||||
94ABD7B41653428B00035061 /* ppu.cpp */,
|
||||
94ABD7B51653428B00035061 /* ppu.h */,
|
||||
94ABD7B61653428B00035061 /* sprite_mapper.cpp */,
|
||||
94ABD7B71653428B00035061 /* sprite_mapper.h */,
|
||||
9499B5C81AB242B200276D21 /* lcddef.h */,
|
||||
9499B5C91AB242B200276D21 /* ly_counter.cpp */,
|
||||
9499B5CA1AB242B200276D21 /* ly_counter.h */,
|
||||
9499B5CB1AB242B200276D21 /* lyc_irq.cpp */,
|
||||
9499B5CC1AB242B200276D21 /* lyc_irq.h */,
|
||||
9499B5CE1AB242B200276D21 /* next_m0_time.cpp */,
|
||||
9499B5CF1AB242B200276D21 /* next_m0_time.h */,
|
||||
9499B5D01AB242B200276D21 /* ppu.cpp */,
|
||||
9499B5D11AB242B200276D21 /* ppu.h */,
|
||||
9499B5D21AB242B200276D21 /* sprite_mapper.cpp */,
|
||||
9499B5D31AB242B200276D21 /* sprite_mapper.h */,
|
||||
);
|
||||
path = video;
|
||||
sourceTree = "<group>";
|
||||
@@ -590,8 +479,7 @@
|
||||
B5A6D9310E617C4900622CCF /* Core */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
94ABD6B1165340E500035061 /* common */,
|
||||
94ABD7681653428B00035061 /* libgambatte */,
|
||||
9499B5421AB242B200276D21 /* src */,
|
||||
);
|
||||
name = Core;
|
||||
sourceTree = "<group>";
|
||||
@@ -622,15 +510,15 @@
|
||||
2A37F4A9FDCFA73011CA2CEA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 0500;
|
||||
LastUpgradeCheck = 1130;
|
||||
};
|
||||
buildConfigurationList = C05733CB08A9546B00998B17 /* Build configuration list for PBXProject "Gambatte" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 2A37F4AAFDCFA73011CA2CEA /* Gambatte */;
|
||||
projectDirPath = "";
|
||||
@@ -648,10 +536,8 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
828387BA0E6CDB6500A96E2C /* Credits.rtf in Resources */,
|
||||
828387BB0E6CDB6500A96E2C /* gameboy.icns in Resources */,
|
||||
828387BD0E6CDB6500A96E2C /* InfoPlist.strings in Resources */,
|
||||
82F45FC50E88979600B7B023 /* Preferences.xib in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -692,44 +578,43 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
94ABD7DA16534BE800035061 /* GBGameCore.mm in Sources */,
|
||||
94ABD7DD16534C8300035061 /* libretro.cpp in Sources */,
|
||||
94ABD6E9165340E500035061 /* chainresampler.cpp in Sources */,
|
||||
94ABD6EA165340E500035061 /* i0.cpp in Sources */,
|
||||
94F2867816C3832E0075A73E /* kaiser50sinc.cpp in Sources */,
|
||||
94F2867916C3832E0075A73E /* kaiser70sinc.cpp in Sources */,
|
||||
94ABD6EB165340E500035061 /* makesinckernel.cpp in Sources */,
|
||||
94ABD6EC165340E500035061 /* resamplerinfo.cpp in Sources */,
|
||||
94ABD6ED165340E500035061 /* u48div.cpp in Sources */,
|
||||
94ABD7BB1653428B00035061 /* bitmap_font.cpp in Sources */,
|
||||
94ABD7BC1653428B00035061 /* cpu.cpp in Sources */,
|
||||
94ABD7BD1653428B00035061 /* file.cpp in Sources */,
|
||||
94ABD7C11653428B00035061 /* gambatte.cpp in Sources */,
|
||||
94ABD7C21653428B00035061 /* initstate.cpp in Sources */,
|
||||
94ABD7C31653428B00035061 /* interrupter.cpp in Sources */,
|
||||
94ABD7C41653428B00035061 /* interruptrequester.cpp in Sources */,
|
||||
94ABD7C51653428B00035061 /* cartridge.cpp in Sources */,
|
||||
94ABD7C61653428B00035061 /* memptrs.cpp in Sources */,
|
||||
94ABD7C71653428B00035061 /* rtc.cpp in Sources */,
|
||||
94ABD7C81653428B00035061 /* memory.cpp in Sources */,
|
||||
94ABD7C91653428B00035061 /* channel1.cpp in Sources */,
|
||||
94ABD7CA1653428B00035061 /* channel2.cpp in Sources */,
|
||||
94ABD7CB1653428B00035061 /* channel3.cpp in Sources */,
|
||||
94ABD7CC1653428B00035061 /* channel4.cpp in Sources */,
|
||||
94ABD7CD1653428B00035061 /* duty_unit.cpp in Sources */,
|
||||
94ABD7CE1653428B00035061 /* envelope_unit.cpp in Sources */,
|
||||
94ABD7CF1653428B00035061 /* length_counter.cpp in Sources */,
|
||||
94ABD7D01653428B00035061 /* sound.cpp in Sources */,
|
||||
94ABD7D11653428B00035061 /* state_osd_elements.cpp in Sources */,
|
||||
94ABD7D21653428B00035061 /* statesaver.cpp in Sources */,
|
||||
94ABD7D31653428B00035061 /* tima.cpp in Sources */,
|
||||
94ABD7D41653428B00035061 /* ly_counter.cpp in Sources */,
|
||||
94ABD7D51653428B00035061 /* lyc_irq.cpp in Sources */,
|
||||
94ABD7D61653428B00035061 /* next_m0_time.cpp in Sources */,
|
||||
94ABD7D71653428B00035061 /* ppu.cpp in Sources */,
|
||||
94ABD7D81653428B00035061 /* sprite_mapper.cpp in Sources */,
|
||||
94ABD7D91653428B00035061 /* video.cpp in Sources */,
|
||||
94F2867D16C383E20075A73E /* loadres.cpp in Sources */,
|
||||
94F2868016C3840F0075A73E /* pakinfo.cpp in Sources */,
|
||||
9499B5D81AB242B200276D21 /* chainresampler.cpp in Sources */,
|
||||
9499B5D91AB242B200276D21 /* i0.cpp in Sources */,
|
||||
9499B5DA1AB242B200276D21 /* kaiser50sinc.cpp in Sources */,
|
||||
9499B5DB1AB242B200276D21 /* kaiser70sinc.cpp in Sources */,
|
||||
9499B5DC1AB242B200276D21 /* makesinckernel.cpp in Sources */,
|
||||
9499B5DD1AB242B200276D21 /* resamplerinfo.cpp in Sources */,
|
||||
9499B5DE1AB242B200276D21 /* u48div.cpp in Sources */,
|
||||
9499B5E81AB242B300276D21 /* bitmap_font.cpp in Sources */,
|
||||
9499B5E91AB242B300276D21 /* cpu.cpp in Sources */,
|
||||
9499B5EA1AB242B300276D21 /* file.cpp in Sources */,
|
||||
9499B5EE1AB242B300276D21 /* gambatte.cpp in Sources */,
|
||||
9499B5EF1AB242B300276D21 /* initstate.cpp in Sources */,
|
||||
9499B5F01AB242B300276D21 /* interrupter.cpp in Sources */,
|
||||
9499B5F11AB242B300276D21 /* interruptrequester.cpp in Sources */,
|
||||
9499B5F21AB242B300276D21 /* loadres.cpp in Sources */,
|
||||
9499B5F71AB242B300276D21 /* memory.cpp in Sources */,
|
||||
9499B5FF1AB242B300276D21 /* sound.cpp in Sources */,
|
||||
9499B6001AB242B300276D21 /* state_osd_elements.cpp in Sources */,
|
||||
8F14C4F929FF7217000D080B /* statesaver.cpp in Sources */,
|
||||
9499B6021AB242B300276D21 /* tima.cpp in Sources */,
|
||||
9499B6081AB242B300276D21 /* video.cpp in Sources */,
|
||||
9499B5F31AB242B300276D21 /* cartridge.cpp in Sources */,
|
||||
9499B5F41AB242B300276D21 /* memptrs.cpp in Sources */,
|
||||
9499B5F51AB242B300276D21 /* pakinfo.cpp in Sources */,
|
||||
9499B5F61AB242B300276D21 /* rtc.cpp in Sources */,
|
||||
9499B5F81AB242B300276D21 /* channel1.cpp in Sources */,
|
||||
9499B5F91AB242B300276D21 /* channel2.cpp in Sources */,
|
||||
9499B5FA1AB242B300276D21 /* channel3.cpp in Sources */,
|
||||
9499B5FB1AB242B300276D21 /* channel4.cpp in Sources */,
|
||||
9499B5FC1AB242B300276D21 /* duty_unit.cpp in Sources */,
|
||||
9499B5FD1AB242B300276D21 /* envelope_unit.cpp in Sources */,
|
||||
9499B5FE1AB242B300276D21 /* length_counter.cpp in Sources */,
|
||||
9499B6031AB242B300276D21 /* ly_counter.cpp in Sources */,
|
||||
9499B6041AB242B300276D21 /* lyc_irq.cpp in Sources */,
|
||||
9499B6051AB242B300276D21 /* next_m0_time.cpp in Sources */,
|
||||
9499B6061AB242B300276D21 /* ppu.cpp in Sources */,
|
||||
9499B6071AB242B300276D21 /* sprite_mapper.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -752,19 +637,11 @@
|
||||
089C165FFE840EACC02AAC07 /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
089C1660FE840EACC02AAC07 /* English */,
|
||||
089C1660FE840EACC02AAC07 /* en */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5F6D8AC0E66921B001CA5D3 /* Credits.rtf */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
B5F6D8AD0E66921B001CA5D3 /* English */,
|
||||
);
|
||||
name = Credits.rtf;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
@@ -772,6 +649,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"\"$(PROJECT_DIR)/gambatte\"",
|
||||
@@ -781,6 +659,7 @@
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INSTALL_PATH = "\"$(USER_LIBRARY_DIR)/Application Support/OpenEmu/Cores\"";
|
||||
OTHER_CFLAGS = "-DHAVE_STDINT_H";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.openemu.${PRODUCT_NAME:identifier}";
|
||||
PRODUCT_NAME = Gambatte;
|
||||
SKIP_INSTALL = YES;
|
||||
USER_HEADER_SEARCH_PATHS = "";
|
||||
@@ -792,6 +671,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"\"$(PROJECT_DIR)/gambatte\"",
|
||||
@@ -801,6 +681,7 @@
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INSTALL_PATH = "\"$(USER_LIBRARY_DIR)/Application Support/OpenEmu/Cores\"";
|
||||
OTHER_CFLAGS = "-DHAVE_STDINT_H";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.openemu.${PRODUCT_NAME:identifier}";
|
||||
PRODUCT_NAME = Gambatte;
|
||||
SKIP_INSTALL = YES;
|
||||
USER_HEADER_SEARCH_PATHS = "";
|
||||
@@ -853,25 +734,43 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = c99;
|
||||
GCC_INCREASE_PRECOMPILED_HEADER_SHARING = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = GL_SILENCE_DEPRECATION;
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
|
||||
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.7;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
@@ -882,26 +781,43 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = c99;
|
||||
GCC_INCREASE_PRECOMPILED_HEADER_SHARING = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 3;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = GL_SILENCE_DEPRECATION;
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
|
||||
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.7;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
name = Release;
|
||||
|
||||
+12
-4
@@ -3,13 +3,13 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>gameboy</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.openemu.${PRODUCT_NAME:identifier}</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.5.0.1</string>
|
||||
<string>0.5.1</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>OEGameCoreController</string>
|
||||
<key>OEGameCoreClass</key>
|
||||
@@ -26,14 +26,22 @@
|
||||
<dict>
|
||||
<key>openemu.system.gb</key>
|
||||
<dict>
|
||||
<key>OEGameCoreRewindBufferSeconds</key>
|
||||
<integer>60</integer>
|
||||
<key>OEGameCoreRewindInterval</key>
|
||||
<integer>0</integer>
|
||||
<key>OEGameCoreSupportsCheatCode</key>
|
||||
<true/>
|
||||
<key>OEGameCoreSupportsDisplayModeChange</key>
|
||||
<true/>
|
||||
<key>OEGameCoreSupportsRewinding</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>OEGameCorePlayerCount</key>
|
||||
<string>1</string>
|
||||
<key>OEProjectURL</key>
|
||||
<string>http://gambatte.sourceforge.net/</string>
|
||||
<string>https://gitlab.com/jgemu/gambatte</string>
|
||||
<key>OESystemIdentifiers</key>
|
||||
<array>
|
||||
<string>openemu.system.gb</string>
|
||||
|
||||
-103
@@ -1,103 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1060</int>
|
||||
<string key="IBDocument.SystemVersion">11C74</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">1938</string>
|
||||
<string key="IBDocument.AppKitVersion">1138.23</string>
|
||||
<string key="IBDocument.HIToolboxVersion">567.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="NS.object.0">1938</string>
|
||||
</object>
|
||||
<array key="IBDocument.IntegratedClassDependencies">
|
||||
<string>NSCustomView</string>
|
||||
<string>NSCustomObject</string>
|
||||
</array>
|
||||
<array key="IBDocument.PluginDependencies">
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</array>
|
||||
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
||||
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
|
||||
<integer value="1" key="NS.object.0"/>
|
||||
</object>
|
||||
<array class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
|
||||
<object class="NSCustomObject" id="1001">
|
||||
<string key="NSClassName">NSObject</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="1003">
|
||||
<string key="NSClassName">FirstResponder</string>
|
||||
</object>
|
||||
<object class="NSCustomObject" id="1004">
|
||||
<string key="NSClassName">NSApplication</string>
|
||||
</object>
|
||||
<object class="NSCustomView" id="1005">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">268</int>
|
||||
<string key="NSFrameSize">{480, 272}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<string key="NSClassName">NSView</string>
|
||||
</object>
|
||||
</array>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
<array class="NSMutableArray" key="connectionRecords"/>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<array key="orderedObjects">
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">0</int>
|
||||
<array key="object" id="0"/>
|
||||
<reference key="children" ref="1000"/>
|
||||
<nil key="parent"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="1001"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-1</int>
|
||||
<reference key="object" ref="1003"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">First Responder</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-3</int>
|
||||
<reference key="object" ref="1004"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">Application</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">1</int>
|
||||
<reference key="object" ref="1005"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
<dictionary class="NSMutableDictionary" key="flattenedProperties">
|
||||
<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</dictionary>
|
||||
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
|
||||
<nil key="activeLocalization"/>
|
||||
<dictionary class="NSMutableDictionary" key="localizations"/>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">1</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes"/>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
|
||||
<real value="1060" key="NS.object.0"/>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
|
||||
<real value="4200" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
</data>
|
||||
</archive>
|
||||
@@ -0,0 +1,58 @@
|
||||
Gambatte JG
|
||||
-----------
|
||||
Gambatte JG is an emulator for the Nintendo Game Boy/Game Boy Color.
|
||||
|
||||
This is a fork of the final public revision of Gambatte.
|
||||
|
||||
This repository lives at https://gitlab.com/jgemu/gambatte
|
||||
|
||||
Compiling
|
||||
---------
|
||||
Make sure you have The Jolly Good API's header files installed. If you did
|
||||
not install them, you will be required to include their path in CXXFLAGS.
|
||||
|
||||
GNU Make's default behaviour for compiling C++ sources is to use g++. If your
|
||||
platform of choice uses an unpatched GNU Make, you will need to override the
|
||||
CXX implicit variable if you wish to use a different compiler.
|
||||
|
||||
Options:
|
||||
USE_VENDORED_SOXR - Set non-zero to use vendored soxr
|
||||
|
||||
Linux:
|
||||
make
|
||||
|
||||
macOS:
|
||||
make
|
||||
|
||||
BSD:
|
||||
gmake
|
||||
|
||||
Windows (MSYS2):
|
||||
make
|
||||
|
||||
The build will be output to "gambatte/". This directory may be used as is
|
||||
locally by copying it to your local "cores" directory, or may be installed
|
||||
system-wide using the "install" target specified in the Makefile.
|
||||
|
||||
Settings
|
||||
--------
|
||||
palette = 0
|
||||
0 = Internal, 1 = Original Green, 2 = GB Pocket, 3 = Blue, 4 = Brown,
|
||||
5 = Dark Blue, 6 = Dark Brown, 7 = Dark Green, 8 = Grayscale, 9 = Green,
|
||||
10 = Inverted, 11 = Orange, 12 = Pastel Mix, 13 = Red, 14 = Yellow
|
||||
|
||||
system = 0
|
||||
0 = Auto (CGB), 1 = DMG, 2 = GBA-CGB
|
||||
|
||||
turbo_rate = 3
|
||||
N = Pulse every N frames
|
||||
|
||||
Copyright
|
||||
---------
|
||||
Gambatte JG (GPL-2.0-or-later)
|
||||
Copyright (c) 2007-2020 Sindre Aamås
|
||||
Copyright (c) 2020-2022 Rupert Carmichael
|
||||
|
||||
SoX Resampler Library (LGPL-2.1-or-later)
|
||||
Copyright (c) 2007-2018 Rob Sykes
|
||||
See source files in deps/soxr/ (https://sourceforge.net/projects/soxr/)
|
||||
@@ -1,56 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "adaptivesleep.h"
|
||||
|
||||
usec_t AdaptiveSleep::sleepUntil(usec_t base, usec_t inc) {
|
||||
usec_t now = getusecs();
|
||||
usec_t diff = now - base;
|
||||
|
||||
if (diff >= inc)
|
||||
return diff - inc;
|
||||
|
||||
diff = inc - diff;
|
||||
|
||||
if (diff > oversleep + oversleepVar) {
|
||||
diff -= oversleep + oversleepVar;
|
||||
usecsleep(diff);
|
||||
const usec_t ideal = now + diff;
|
||||
now = getusecs();
|
||||
|
||||
{
|
||||
usec_t curOversleep = now - ideal;
|
||||
|
||||
if (negate(curOversleep) < curOversleep)
|
||||
curOversleep = 0;
|
||||
|
||||
oversleepVar = (oversleepVar * 15 + (curOversleep < oversleep ? oversleep - curOversleep : curOversleep - oversleep) + 8) >> 4;
|
||||
oversleep = (oversleep * 15 + curOversleep + 8) >> 4;
|
||||
}
|
||||
|
||||
noSleep = 60;
|
||||
} else if (--noSleep == 0) {
|
||||
noSleep = 60;
|
||||
oversleep = oversleepVar = 0;
|
||||
}
|
||||
|
||||
while (now - base < inc)
|
||||
now = getusecs();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef ADAPTIVE_SLEEP_H
|
||||
#define ADAPTIVE_SLEEP_H
|
||||
|
||||
#include "usec.h"
|
||||
|
||||
class AdaptiveSleep {
|
||||
usec_t oversleep;
|
||||
usec_t oversleepVar;
|
||||
unsigned noSleep;
|
||||
|
||||
public:
|
||||
AdaptiveSleep() : oversleep(0), oversleepVar(0), noSleep(60) {}
|
||||
usec_t sleepUntil(usec_t base, usec_t inc);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,94 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "rateest.h"
|
||||
#include <cstdlib>
|
||||
|
||||
void RateEst::SumQueue::reset() {
|
||||
q.clear();
|
||||
samples_ = usecs_ = 0;
|
||||
}
|
||||
|
||||
void RateEst::SumQueue::push(const long samples, const usec_t usecs) {
|
||||
q.push_back(pair_t(samples, usecs));
|
||||
samples_ += samples;
|
||||
usecs_ += usecs;
|
||||
}
|
||||
|
||||
void RateEst::SumQueue::pop() {
|
||||
const pair_t &f = q.front();
|
||||
samples_ -= f.first;
|
||||
usecs_ -= f.second;
|
||||
q.pop_front();
|
||||
}
|
||||
|
||||
static usec_t sampleUsecs(long samples, long rate) {
|
||||
return static_cast<usec_t>((samples * 1000000.0f) / (rate ? rate : 1) + 0.5f);
|
||||
}
|
||||
|
||||
static long limit(long est, const long reference) {
|
||||
if (est > reference + (reference >> 6))
|
||||
est = reference + (reference >> 6);
|
||||
else if (est < reference - (reference >> 6))
|
||||
est = reference - (reference >> 6);
|
||||
|
||||
return est;
|
||||
}
|
||||
|
||||
void RateEst::init(long srate, long reference, const long maxSamplePeriod) {
|
||||
maxPeriod = sampleUsecs(maxSamplePeriod, reference);
|
||||
|
||||
srate <<= UPSHIFT;
|
||||
reference <<= UPSHIFT;
|
||||
|
||||
this->srate = limit(srate, reference);
|
||||
last = 0;
|
||||
this->reference = reference;
|
||||
samples = ((this->srate >> UPSHIFT) * 12) << 5;
|
||||
usecs = 12000000 << 5;
|
||||
sumq.reset();
|
||||
}
|
||||
|
||||
void RateEst::feed(long samplesIn, const usec_t now) {
|
||||
usec_t usecsIn = now - last;
|
||||
|
||||
if (last && usecsIn < maxPeriod) {
|
||||
sumq.push(samplesIn, usecsIn);
|
||||
|
||||
while ((usecsIn = sumq.usecs()) > 100000) {
|
||||
samplesIn = sumq.samples();
|
||||
sumq.pop();
|
||||
|
||||
if (std::abs(static_cast<long>(samplesIn * (1000000.0f * UP) / usecsIn) - reference) < reference >> 1) {
|
||||
samples += (samplesIn - sumq.samples()) << 5;
|
||||
usecs += (usecsIn - sumq.usecs()) << 5;
|
||||
|
||||
long est = static_cast<long>(samples * (1000000.0f * UP) / usecs + 0.5f);
|
||||
est = limit((srate * 31 + est + 16) >> 5, reference);
|
||||
srate = est;
|
||||
|
||||
if (usecs > 16000000 << 5) {
|
||||
samples = (samples * 3 + 2) >> 2;
|
||||
usecs = (usecs * 3 + 2) >> 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last = now;
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef RATEEST_H
|
||||
#define RATEEST_H
|
||||
|
||||
#include "usec.h"
|
||||
#include <deque>
|
||||
#include <utility>
|
||||
|
||||
class RateEst {
|
||||
class SumQueue {
|
||||
typedef std::pair<long, usec_t> pair_t;
|
||||
typedef std::deque<pair_t> q_t;
|
||||
|
||||
q_t q;
|
||||
long samples_;
|
||||
usec_t usecs_;
|
||||
|
||||
public:
|
||||
SumQueue() : samples_(0), usecs_(0) {}
|
||||
void reset();
|
||||
long samples() const { return samples_; }
|
||||
usec_t usecs() const { return usecs_; }
|
||||
void push(long samples, usec_t usecs);
|
||||
void pop();
|
||||
};
|
||||
|
||||
enum { UPSHIFT = 5 };
|
||||
enum { UP = 1 << UPSHIFT };
|
||||
|
||||
long srate;
|
||||
SumQueue sumq;
|
||||
usec_t last;
|
||||
usec_t usecs;
|
||||
usec_t maxPeriod;
|
||||
long reference;
|
||||
long samples;
|
||||
|
||||
public:
|
||||
explicit RateEst(long srate = 0) { init(srate); }
|
||||
RateEst(long srate, long reference) { init(srate, reference); }
|
||||
void init(long srate) { init(srate, srate); }
|
||||
void init(long srate, long reference) { init(srate, reference, reference); }
|
||||
void init(long srate, long reference, long maxSamplePeriod);
|
||||
void reset() { last = 0; }
|
||||
void feed(long samples, usec_t usecs = getusecs());
|
||||
long result() const { return (srate + UP / 2) >> UPSHIFT; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,170 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "chainresampler.h"
|
||||
|
||||
float ChainResampler::get2ChainMidRatio(const float ratio, const float finalRollOffLen, const float midRollOffStartPlusEnd) {
|
||||
return 0.5f * (std::sqrt(ratio * midRollOffStartPlusEnd * finalRollOffLen) + midRollOffStartPlusEnd);
|
||||
}
|
||||
|
||||
float ChainResampler::get2ChainCost(const float ratio, const float finalRollOffLen, const float midRatio, const float midRollOffStartPlusEnd) {
|
||||
const float midRollOffLen = midRatio * 2 - midRollOffStartPlusEnd;
|
||||
return midRatio * ratio / midRollOffLen + get1ChainCost(midRatio, finalRollOffLen);
|
||||
}
|
||||
|
||||
float ChainResampler::get3ChainRatio1(float ratio1, const float finalRollOffLen, const float ratio, const float midRollOffStartPlusEnd) {
|
||||
for (unsigned n = 8; n--;) {
|
||||
const float ratio2 = get3ChainRatio2(ratio1, finalRollOffLen, midRollOffStartPlusEnd);
|
||||
ratio1 = 0.5f * (std::sqrt(ratio * midRollOffStartPlusEnd * (2 - midRollOffStartPlusEnd / ratio2)) + midRollOffStartPlusEnd);
|
||||
}
|
||||
|
||||
return ratio1;
|
||||
}
|
||||
|
||||
float ChainResampler::get3ChainCost(const float ratio, const float finalRollOffLen,
|
||||
const float ratio1, const float ratio2, const float midRollOffStartPlusEnd) {
|
||||
const float firstRollOffLen = ratio1 * 2 - midRollOffStartPlusEnd;
|
||||
return ratio1 * ratio / firstRollOffLen + get2ChainCost(ratio1, finalRollOffLen, ratio2, midRollOffStartPlusEnd);
|
||||
}
|
||||
|
||||
ChainResampler::ChainResampler()
|
||||
: bigSinc(0), buffer2(0), periodSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
void ChainResampler::downinitAddSincResamplers(double ratio, float const outRate,
|
||||
CreateSinc const createBigSinc, CreateSinc const createSmallSinc,
|
||||
unsigned const bigSincMul, unsigned const smallSincMul, double gain) {
|
||||
// For high outRate: Start roll-off at 36000 Hz continue until outRate Hz, then wrap around back down to 40000 Hz.
|
||||
const float outPeriod = 1.0f / outRate;
|
||||
const float finalRollOffLen = std::max((outRate - 36000.0f + outRate - 40000.0f) * outPeriod, 0.2f);
|
||||
|
||||
{
|
||||
const float midRollOffStart = std::min(36000.0f * outPeriod, 1.0f);
|
||||
const float midRollOffEnd = std::min(40000.0f * outPeriod, 1.0f); // after wrap at folding freq.
|
||||
const float midRollOffStartPlusEnd = midRollOffStart + midRollOffEnd;
|
||||
|
||||
int div_2c = static_cast<int>(ratio * smallSincMul / get2ChainMidRatio(ratio, finalRollOffLen, midRollOffStartPlusEnd) + 0.5f);
|
||||
double ratio_2c = ratio * smallSincMul / div_2c;
|
||||
float cost_2c = get2ChainCost(ratio, finalRollOffLen, ratio_2c, midRollOffStartPlusEnd);
|
||||
|
||||
if (cost_2c < get1ChainCost(ratio, finalRollOffLen)) {
|
||||
const int div1_3c = static_cast<int>(
|
||||
ratio * smallSincMul / get3ChainRatio1(ratio_2c, finalRollOffLen, ratio, midRollOffStartPlusEnd) + 0.5f);
|
||||
const double ratio1_3c = ratio * smallSincMul / div1_3c;
|
||||
const int div2_3c = static_cast<int>(
|
||||
ratio1_3c * smallSincMul / get3ChainRatio2(ratio1_3c, finalRollOffLen, midRollOffStartPlusEnd) + 0.5f);
|
||||
const double ratio2_3c = ratio1_3c * smallSincMul / div2_3c;
|
||||
|
||||
if (get3ChainCost(ratio, finalRollOffLen, ratio1_3c, ratio2_3c, midRollOffStartPlusEnd) < cost_2c) {
|
||||
list.push_back(createSmallSinc(div1_3c, 0.5f * midRollOffStart / ratio,
|
||||
(ratio1_3c - 0.5f * midRollOffStartPlusEnd) / ratio, gain));
|
||||
ratio = ratio1_3c;
|
||||
div_2c = div2_3c;
|
||||
ratio_2c = ratio2_3c;
|
||||
gain = 1.0;
|
||||
}
|
||||
|
||||
list.push_back(createSmallSinc(div_2c, 0.5f * midRollOffStart / ratio,
|
||||
(ratio_2c - 0.5f * midRollOffStartPlusEnd) / ratio, gain));
|
||||
ratio = ratio_2c;
|
||||
gain = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
list.push_back(bigSinc =
|
||||
createBigSinc(static_cast<int>(bigSincMul * ratio + 0.5),
|
||||
0.5f * (1.0f + std::max((outRate - 40000.0f) * outPeriod, 0.0f) - finalRollOffLen) / ratio,
|
||||
0.5f * finalRollOffLen / ratio, gain));
|
||||
}
|
||||
|
||||
std::size_t ChainResampler::reallocateBuffer() {
|
||||
std::size_t bufSz[2] = { 0, 0 };
|
||||
std::size_t inSz = periodSize;
|
||||
int i = -1;
|
||||
|
||||
for (list_t::iterator it = list.begin(); it != list.end(); ++it) {
|
||||
inSz = (inSz * (*it)->mul() - 1) / (*it)->div() + 1;
|
||||
|
||||
++i;
|
||||
|
||||
if (inSz > bufSz[i&1])
|
||||
bufSz[i&1] = inSz;
|
||||
}
|
||||
|
||||
if (inSz >= bufSz[i&1])
|
||||
bufSz[i&1] = 0;
|
||||
|
||||
if (buffer.size() < (bufSz[0] + bufSz[1]) * channels)
|
||||
buffer.reset((bufSz[0] + bufSz[1]) * channels);
|
||||
|
||||
buffer2 = bufSz[1] ? buffer + bufSz[0] * channels : 0;
|
||||
|
||||
return (maxOut_ = inSz);
|
||||
}
|
||||
|
||||
void ChainResampler::adjustRate(const long inRate, const long outRate) {
|
||||
unsigned long mul, div;
|
||||
|
||||
exactRatio(mul, div);
|
||||
|
||||
bigSinc->adjustDiv(static_cast<int>(static_cast<double>(inRate) * mul / (static_cast<double>(div / bigSinc->div()) * outRate) + 0.5));
|
||||
|
||||
reallocateBuffer();
|
||||
setRate(inRate, outRate);
|
||||
}
|
||||
|
||||
void ChainResampler::exactRatio(unsigned long &mul, unsigned long &div) const {
|
||||
mul = 1;
|
||||
div = 1;
|
||||
|
||||
for (list_t::const_iterator it = list.begin(); it != list.end(); ++it) {
|
||||
mul *= (*it)->mul();
|
||||
div *= (*it)->div();
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t ChainResampler::resample(short *const out, const short *const in, std::size_t inlen) {
|
||||
assert(inlen <= periodSize);
|
||||
|
||||
short *const buf = buffer != buffer2 ? buffer : out;
|
||||
short *const buf2 = buffer2 ? buffer2 : out;
|
||||
|
||||
const short *inbuf = in;
|
||||
short *outbuf = 0;
|
||||
|
||||
for (list_t::iterator it = list.begin(); it != list.end(); ++it) {
|
||||
outbuf = ++list_t::iterator(it) == list.end() ? out : (inbuf == buf ? buf2 : buf);
|
||||
inlen = (*it)->resample(outbuf, inbuf, inlen);
|
||||
inbuf = outbuf;
|
||||
}
|
||||
|
||||
return inlen;
|
||||
}
|
||||
|
||||
void ChainResampler::uninit() {
|
||||
buffer2 = 0;
|
||||
buffer.reset();
|
||||
periodSize = 0;
|
||||
bigSinc = 0;
|
||||
|
||||
for (list_t::iterator it = list.begin(); it != list.end(); ++it)
|
||||
delete *it;
|
||||
|
||||
list.clear();
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef CHAINRESAMPLER_H
|
||||
#define CHAINRESAMPLER_H
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <list>
|
||||
#include "array.h"
|
||||
#include "subresampler.h"
|
||||
#include "../resampler.h"
|
||||
#include "upsampler.h"
|
||||
|
||||
class ChainResampler : public Resampler {
|
||||
typedef std::list<SubResampler*> list_t;
|
||||
typedef SubResampler * (*CreateSinc)(unsigned div, float rollOffStart, float rollOffWidth, double gain);
|
||||
|
||||
list_t list;
|
||||
SubResampler *bigSinc;
|
||||
Array<short> buffer;
|
||||
short *buffer2;
|
||||
std::size_t periodSize;
|
||||
std::size_t maxOut_;
|
||||
|
||||
static float get1ChainCost(float ratio, float finalRollOffLen) { return ratio / finalRollOffLen; }
|
||||
|
||||
static float get2ChainMidRatio(float ratio, float finalRollOffLen, float midRollOffStartPlusEnd);
|
||||
static float get2ChainCost(float ratio, float finalRollOffLen, float midRatio, float midRollOffStartPlusEnd);
|
||||
|
||||
static float get3ChainRatio2(float ratio1, float finalRollOffLen, float midRollOffStartPlusEnd) {
|
||||
return get2ChainMidRatio(ratio1, finalRollOffLen, midRollOffStartPlusEnd);
|
||||
}
|
||||
|
||||
static float get3ChainRatio1(float ratio1, float finalRollOffLen, float ratio, float midRollOffStartPlusEnd);
|
||||
static float get3ChainCost(float ratio, float finalRollOffLen, float ratio1, float ratio2, float midRollOffStartPlusEnd);
|
||||
|
||||
void downinitAddSincResamplers(double ratio, float outRate,
|
||||
CreateSinc createBigSinc, CreateSinc createSmallSinc,
|
||||
unsigned bigSincMul, unsigned smallSincMul, double gain);
|
||||
|
||||
template<class Sinc>
|
||||
static SubResampler * createSinc(unsigned div, float rollOffStart, float rollOffWidth, double gain) {
|
||||
return new Sinc(div, typename Sinc::RollOff(rollOffStart, rollOffWidth), gain);
|
||||
}
|
||||
|
||||
template<template<unsigned,unsigned> class Sinc>
|
||||
std::size_t downinit(long inRate, long outRate, std::size_t periodSize);
|
||||
|
||||
template<template<unsigned,unsigned> class Sinc>
|
||||
std::size_t upinit(long inRate, long outRate, std::size_t periodSize);
|
||||
|
||||
std::size_t reallocateBuffer();
|
||||
|
||||
public:
|
||||
enum { channels = 2 };
|
||||
ChainResampler();
|
||||
~ChainResampler() { uninit(); }
|
||||
|
||||
void adjustRate(long inRate, long outRate);
|
||||
void exactRatio(unsigned long &mul, unsigned long &div) const;
|
||||
|
||||
template<template<unsigned,unsigned> class Sinc>
|
||||
std::size_t init(long inRate, long outRate, std::size_t periodSize);
|
||||
std::size_t maxOut(std::size_t /*inlen*/) const { return maxOut_; }
|
||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
||||
void uninit();
|
||||
};
|
||||
|
||||
template<template<unsigned,unsigned> class Sinc>
|
||||
std::size_t ChainResampler::init(const long inRate, const long outRate, const std::size_t periodSize) {
|
||||
setRate(inRate, outRate);
|
||||
|
||||
if (outRate > inRate)
|
||||
return upinit<Sinc>(inRate, outRate, periodSize);
|
||||
else
|
||||
return downinit<Sinc>(inRate, outRate, periodSize);
|
||||
}
|
||||
|
||||
template<template<unsigned,unsigned> class Sinc>
|
||||
std::size_t ChainResampler::downinit(const long inRate, const long outRate, const std::size_t periodSize) {
|
||||
typedef Sinc<channels,2048> BigSinc;
|
||||
typedef Sinc<channels, 32> SmallSinc;
|
||||
|
||||
uninit();
|
||||
this->periodSize = periodSize;
|
||||
|
||||
double ratio = static_cast<double>(inRate) / outRate;
|
||||
double gain = 1.0;
|
||||
|
||||
while (ratio >= BigSinc::cicLimit() * 2) {
|
||||
const int div = std::min<int>(static_cast<int>(ratio / BigSinc::cicLimit()), BigSinc::Cic::MAX_DIV);
|
||||
list.push_back(new typename BigSinc::Cic(div));
|
||||
ratio /= div;
|
||||
gain *= 1.0 / BigSinc::Cic::gain(div);
|
||||
}
|
||||
|
||||
downinitAddSincResamplers(ratio, outRate, createSinc<BigSinc>,
|
||||
createSinc<SmallSinc>, BigSinc::MUL, SmallSinc::MUL, gain);
|
||||
|
||||
return reallocateBuffer();
|
||||
}
|
||||
|
||||
template<template<unsigned,unsigned> class Sinc>
|
||||
std::size_t ChainResampler::upinit(const long inRate, const long outRate, const std::size_t periodSize) {
|
||||
typedef Sinc<channels,2048> BigSinc;
|
||||
typedef Sinc<channels,32> SmallSinc;
|
||||
|
||||
uninit();
|
||||
this->periodSize = periodSize;
|
||||
|
||||
double ratio = static_cast<double>(outRate) / inRate;
|
||||
|
||||
// Spectral images above 20 kHz assumed inaudible
|
||||
{
|
||||
const int div = outRate / std::max(inRate, 40000l);
|
||||
|
||||
if (div >= 2) {
|
||||
list.push_front(new Upsampler<channels>(div));
|
||||
ratio /= div;
|
||||
}
|
||||
}
|
||||
|
||||
const float rollOff = std::max((inRate - 36000.0f) / inRate, 0.2f);
|
||||
|
||||
/*{
|
||||
int div_2c = get2ChainMidRatio(ratio, rollOff) * SmallSinc::MUL / ratio + 0.5f;
|
||||
double ratio_2c = ratio * div_2c / SmallSinc::MUL;
|
||||
float cost_2c = get2ChainCost(ratio, rollOff, ratio_2c);
|
||||
|
||||
if (cost_2c < get1ChainCost(ratio, rollOff)) {
|
||||
const int div1_3c = get3ChainRatio1(ratio_2c, rollOff, ratio) * SmallSinc::MUL / ratio + 0.5f;
|
||||
const double ratio1_3c = ratio * div1_3c / SmallSinc::MUL;
|
||||
const int div2_3c = get3ChainRatio2(ratio1_3c, rollOff) * SmallSinc::MUL / ratio1_3c + 0.5f;
|
||||
const double ratio2_3c = ratio1_3c * div2_3c / SmallSinc::MUL;
|
||||
|
||||
if (get3ChainCost(ratio, rollOff, ratio1_3c, ratio2_3c) < cost_2c) {
|
||||
list.push_front(new SmallSinc(div1_3c, typename SmallSinc::RollOff(0.5f / ratio1_3c, (ratio1_3c - 1) / ratio1_3c), 1.0));
|
||||
ratio = ratio1_3c;
|
||||
div_2c = div2_3c;
|
||||
ratio_2c = ratio2_3c;
|
||||
}
|
||||
|
||||
list.push_front(new SmallSinc(div_2c, typename SmallSinc::RollOff(0.5f / ratio_2c, (ratio_2c - 1) / ratio_2c), 1.0));
|
||||
ratio = ratio_2c;
|
||||
}
|
||||
}*/
|
||||
|
||||
list.push_front(bigSinc = new BigSinc(static_cast<int>(BigSinc::MUL / ratio + 0.5),
|
||||
typename BigSinc::RollOff(0.5f * (1 - rollOff), 0.5f * rollOff), 1.0));
|
||||
|
||||
return reallocateBuffer();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,244 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef CIC2_H
|
||||
#define CIC2_H
|
||||
|
||||
#include "subresampler.h"
|
||||
#include "rshift16_round.h"
|
||||
|
||||
template<unsigned channels>
|
||||
class Cic2Core {
|
||||
// enum { BUFLEN = 64 };
|
||||
// unsigned long buf[BUFLEN];
|
||||
unsigned long sum1;
|
||||
unsigned long sum2;
|
||||
unsigned long prev1;
|
||||
// unsigned long prev2;
|
||||
unsigned div_;
|
||||
unsigned nextdivn;
|
||||
// unsigned bufpos;
|
||||
|
||||
// trouble if div is too large, may be better to only support power of 2 div
|
||||
static long mulForDiv(unsigned div) { return 0x10000 / (div * div); }
|
||||
|
||||
public:
|
||||
explicit Cic2Core(const unsigned div = 2) { reset(div); }
|
||||
unsigned div() const { return div_; }
|
||||
std::size_t filter(short *out, const short *in, std::size_t inlen);
|
||||
void reset(unsigned div);
|
||||
static double gain(unsigned div) { return rshift16_round(-32768l * (div * div) * mulForDiv(div)) / -32768.0; }
|
||||
};
|
||||
|
||||
template<unsigned channels>
|
||||
void Cic2Core<channels>::reset(const unsigned div) {
|
||||
sum2 = sum1 = 0;
|
||||
/*prev2 = */prev1 = 0;
|
||||
this->div_ = div;
|
||||
nextdivn = div;
|
||||
// bufpos = div - 1;
|
||||
}
|
||||
|
||||
template<unsigned channels>
|
||||
std::size_t Cic2Core<channels>::filter(short *out, const short *const in, std::size_t inlen) {
|
||||
// const std::size_t produced = (inlen + div_ - (bufpos + 1)) / div_;
|
||||
const std::size_t produced = (inlen + div_ - nextdivn) / div_;
|
||||
const long mul = mulForDiv(div_);
|
||||
const short *s = in;
|
||||
|
||||
/*unsigned long sm1 = sum1;
|
||||
unsigned long sm2 = sum2;
|
||||
|
||||
while (inlen >> 2) {
|
||||
unsigned n = (inlen < BUFLEN ? inlen >> 2 : BUFLEN >> 2);
|
||||
const unsigned end = n * 4;
|
||||
unsigned i = 0;
|
||||
|
||||
do {
|
||||
unsigned long s1 = sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
buf[i++] = sm2 += s1;
|
||||
buf[i++] = sm2 += sm1;
|
||||
s1 = sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
buf[i++] = sm2 += s1;
|
||||
buf[i++] = sm2 += sm1;
|
||||
} while (--n);
|
||||
|
||||
while (bufpos < end) {
|
||||
const unsigned long out2 = buf[bufpos] - prev2;
|
||||
prev2 = buf[bufpos];
|
||||
bufpos += div_;
|
||||
|
||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
||||
prev1 = out2;
|
||||
out += channels;
|
||||
}
|
||||
|
||||
bufpos -= end;
|
||||
inlen -= end;
|
||||
}
|
||||
|
||||
if (inlen) {
|
||||
unsigned n = inlen;
|
||||
unsigned i = 0;
|
||||
|
||||
do {
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
buf[i++] = sm2 += sm1;
|
||||
} while (--n);
|
||||
|
||||
while (bufpos < inlen) {
|
||||
const unsigned long out2 = buf[bufpos] - prev2;
|
||||
prev2 = buf[bufpos];
|
||||
bufpos += div_;
|
||||
|
||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
||||
prev1 = out2;
|
||||
out += channels;
|
||||
}
|
||||
|
||||
bufpos -= inlen;
|
||||
}
|
||||
|
||||
sum1 = sm1;
|
||||
sum2 = sm2;*/
|
||||
|
||||
unsigned long sm1 = sum1;
|
||||
unsigned long sm2 = sum2;
|
||||
|
||||
if (inlen >= nextdivn) {
|
||||
{
|
||||
unsigned divn = nextdivn;
|
||||
|
||||
do {
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm2 += sm1;
|
||||
} while (--divn);
|
||||
|
||||
const unsigned long out2 = sm2;
|
||||
sm2 = 0;
|
||||
|
||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
||||
prev1 = out2;
|
||||
out += channels;
|
||||
}
|
||||
|
||||
if (div_ & 1) {
|
||||
std::size_t n = produced;
|
||||
|
||||
while (--n) {
|
||||
unsigned divn = div_ >> 1;
|
||||
|
||||
do {
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm2 += sm1;
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm2 += sm1;
|
||||
} while (--divn);
|
||||
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm2 += sm1;
|
||||
|
||||
*out = rshift16_round(static_cast<long>(sm2 - prev1) * mul);
|
||||
out += channels;
|
||||
prev1 = sm2;
|
||||
sm2 = 0;
|
||||
}
|
||||
} else {
|
||||
std::size_t n = produced;
|
||||
|
||||
while (--n) {
|
||||
unsigned divn = div_ >> 1;
|
||||
|
||||
do {
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm2 += sm1;
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm2 += sm1;
|
||||
} while (--divn);
|
||||
|
||||
*out = rshift16_round(static_cast<long>(sm2 - prev1) * mul);
|
||||
out += channels;
|
||||
prev1 = sm2;
|
||||
sm2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
nextdivn = div_;
|
||||
}
|
||||
|
||||
{
|
||||
unsigned divn = (in + inlen * channels - s) / channels;
|
||||
nextdivn -= divn;
|
||||
|
||||
while (divn--) {
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm2 += sm1;
|
||||
}
|
||||
}
|
||||
|
||||
sum1 = sm1;
|
||||
sum2 = sm2;
|
||||
|
||||
return produced;
|
||||
}
|
||||
|
||||
template<unsigned channels>
|
||||
class Cic2 : public SubResampler {
|
||||
Cic2Core<channels> cics[channels];
|
||||
|
||||
public:
|
||||
enum { MAX_DIV = 64 };
|
||||
explicit Cic2(unsigned div);
|
||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
||||
unsigned mul() const { return 1; }
|
||||
unsigned div() const { return cics[0].div(); }
|
||||
static double gain(unsigned div) { return Cic2Core<channels>::gain(div); }
|
||||
};
|
||||
|
||||
template<unsigned channels>
|
||||
Cic2<channels>::Cic2(const unsigned div) {
|
||||
for (unsigned i = 0; i < channels; ++i)
|
||||
cics[i].reset(div);
|
||||
}
|
||||
|
||||
template<unsigned channels>
|
||||
std::size_t Cic2<channels>::resample(short *const out, const short *const in, const std::size_t inlen) {
|
||||
std::size_t samplesOut;
|
||||
|
||||
for (unsigned i = 0; i < channels; ++i) {
|
||||
samplesOut = cics[i].filter(out + i, in + i, inlen);
|
||||
}
|
||||
|
||||
return samplesOut;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,380 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef CIC3_H
|
||||
#define CIC3_H
|
||||
|
||||
#include "subresampler.h"
|
||||
#include "rshift16_round.h"
|
||||
|
||||
template<unsigned channels>
|
||||
class Cic3Core {
|
||||
// enum { BUFLEN = 64 };
|
||||
// unsigned long buf[BUFLEN];
|
||||
unsigned long sum1;
|
||||
unsigned long sum2;
|
||||
unsigned long sum3;
|
||||
unsigned long prev1;
|
||||
unsigned long prev2;
|
||||
unsigned div_;
|
||||
unsigned nextdivn;
|
||||
// unsigned bufpos;
|
||||
|
||||
// trouble if div is too large, may be better to only support power of 2 div
|
||||
static long mulForDiv(unsigned div) { return 0x10000 / (div * div * div); }
|
||||
|
||||
public:
|
||||
explicit Cic3Core(const unsigned div = 1) { reset(div); }
|
||||
unsigned div() const { return div_; }
|
||||
std::size_t filter(short *out, const short *in, std::size_t inlen);
|
||||
void reset(unsigned div);
|
||||
static double gain(unsigned div) { return rshift16_round(-32768l * (div * div * div) * mulForDiv(div)) / -32768.0; }
|
||||
};
|
||||
|
||||
template<unsigned channels>
|
||||
void Cic3Core<channels>::reset(const unsigned div) {
|
||||
sum3 = sum2 = sum1 = 0;
|
||||
prev2 = prev1 = 0;
|
||||
this->div_ = div;
|
||||
nextdivn = div;
|
||||
// bufpos = div - 1;
|
||||
}
|
||||
|
||||
template<unsigned channels>
|
||||
std::size_t Cic3Core<channels>::filter(short *out, const short *const in, std::size_t inlen) {
|
||||
// const std::size_t produced = (inlen + div_ - (bufpos + 1)) / div_;
|
||||
const std::size_t produced = (inlen + div_ - nextdivn) / div_;
|
||||
const short *s = in;
|
||||
|
||||
/*unsigned long sm1 = sum1;
|
||||
unsigned long sm2 = sum2;
|
||||
unsigned long sm3 = sum3;
|
||||
|
||||
while (inlen >> 1) {
|
||||
unsigned n = (inlen < BUFLEN ? inlen >> 1 : BUFLEN >> 1);
|
||||
const unsigned end = n * 2;
|
||||
unsigned i = 0;
|
||||
|
||||
do {
|
||||
unsigned long s1 = sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
unsigned long s2 = sm2 += s1;
|
||||
sm2 += sm1;
|
||||
buf[i++] = sm3 += s2;
|
||||
buf[i++] = sm3 += sm2;
|
||||
} while (--n);
|
||||
|
||||
while (bufpos < end) {
|
||||
const unsigned long out3 = buf[bufpos] - prev3;
|
||||
prev3 = buf[bufpos];
|
||||
bufpos += div_;
|
||||
|
||||
const unsigned long out2 = out3 - prev2;
|
||||
prev2 = out3;
|
||||
|
||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
||||
prev1 = out2;
|
||||
out += channels;
|
||||
}
|
||||
|
||||
bufpos -= end;
|
||||
inlen -= end;
|
||||
}
|
||||
|
||||
if (inlen) {
|
||||
unsigned n = inlen;
|
||||
unsigned i = 0;
|
||||
|
||||
do {
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm2 += sm1;
|
||||
buf[i++] = sm3 += sm2;
|
||||
} while (--n);
|
||||
|
||||
while (bufpos < inlen) {
|
||||
const unsigned long out3 = buf[bufpos] - prev3;
|
||||
prev3 = buf[bufpos];
|
||||
bufpos += div_;
|
||||
|
||||
const unsigned long out2 = out3 - prev2;
|
||||
prev2 = out3;
|
||||
|
||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
||||
prev1 = out2;
|
||||
out += channels;
|
||||
}
|
||||
|
||||
bufpos -= inlen;
|
||||
}
|
||||
|
||||
sum1 = sm1;
|
||||
sum2 = sm2;
|
||||
sum3 = sm3;*/
|
||||
|
||||
|
||||
unsigned long sm1 = sum1;
|
||||
unsigned long sm2 = sum2;
|
||||
unsigned long sm3 = sum3;
|
||||
|
||||
if (inlen >= nextdivn) {
|
||||
const long mul = mulForDiv(div_);
|
||||
unsigned divn = nextdivn;
|
||||
std::size_t n = produced;
|
||||
|
||||
do {
|
||||
do {
|
||||
sm1 += static_cast<long>(*s);
|
||||
sm2 += sm1;
|
||||
sm3 += sm2;
|
||||
s += channels;
|
||||
} while (--divn);
|
||||
|
||||
const unsigned long out2 = sm3 - prev2;
|
||||
prev2 = sm3;
|
||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
||||
prev1 = out2;
|
||||
out += channels;
|
||||
divn = div_;
|
||||
sm3 = 0;
|
||||
} while (--n);
|
||||
|
||||
nextdivn = div_;
|
||||
}
|
||||
|
||||
{
|
||||
unsigned divn = (in + inlen * channels - s) / channels;
|
||||
nextdivn -= divn;
|
||||
|
||||
while (divn--) {
|
||||
sm1 += static_cast<long>(*s);
|
||||
sm2 += sm1;
|
||||
sm3 += sm2;
|
||||
s += channels;
|
||||
}
|
||||
}
|
||||
|
||||
sum1 = sm1;
|
||||
sum2 = sm2;
|
||||
sum3 = sm3;
|
||||
|
||||
return produced;
|
||||
}
|
||||
|
||||
/*template<unsigned channels>
|
||||
class Cic3EvenOddCore {
|
||||
unsigned long sum1;
|
||||
unsigned long sum2;
|
||||
unsigned long sum3;
|
||||
unsigned long prev1;
|
||||
unsigned long prev2;
|
||||
unsigned long prev3;
|
||||
unsigned div_;
|
||||
unsigned nextdivn;
|
||||
|
||||
static int getMul(unsigned div) {
|
||||
return 0x10000 / (div * div * div); // trouble if div is too large, may be better to only support power of 2 div
|
||||
}
|
||||
|
||||
void filterEven(short *out, const short *s, std::size_t n);
|
||||
void filterOdd(short *out, const short *s, std::size_t n);
|
||||
|
||||
public:
|
||||
Cic3EvenOddCore(const unsigned div = 2) {
|
||||
reset(div);
|
||||
}
|
||||
|
||||
unsigned div() const { return div_; }
|
||||
std::size_t filter(short *out, const short *in, std::size_t inlen);
|
||||
void reset(unsigned div);
|
||||
};
|
||||
|
||||
template<unsigned channels>
|
||||
void Cic3EvenOddCore<channels>::reset(const unsigned div) {
|
||||
sum3 = sum2 = sum1 = 0;
|
||||
prev3 = prev2 = prev1 = 0;
|
||||
this->div_ = div;
|
||||
nextdivn = div;
|
||||
}
|
||||
|
||||
template<unsigned channels>
|
||||
void Cic3EvenOddCore<channels>::filterEven(short *out, const short *s, std::size_t n) {
|
||||
const int mul = getMul(div_);
|
||||
unsigned long sm1 = sum1;
|
||||
unsigned long sm2 = sum2;
|
||||
unsigned long sm3 = sum3;
|
||||
|
||||
while (n--) {
|
||||
{
|
||||
unsigned sn = div_ >> 1;
|
||||
|
||||
do {
|
||||
unsigned long s1 = sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
unsigned long s2 = sm2 += s1;
|
||||
sm2 += sm1;
|
||||
sm3 += s2;
|
||||
sm3 += sm2;
|
||||
} while (--sn);
|
||||
}
|
||||
|
||||
const unsigned long out3 = sm3 - prev3;
|
||||
prev3 = sm3;
|
||||
const unsigned long out2 = out3 - prev2;
|
||||
prev2 = out3;
|
||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
||||
prev1 = out2;
|
||||
out += channels;
|
||||
}
|
||||
|
||||
sum1 = sm1;
|
||||
sum2 = sm2;
|
||||
sum3 = sm3;
|
||||
}
|
||||
|
||||
template<unsigned channels>
|
||||
void Cic3EvenOddCore<channels>::filterOdd(short *out, const short *s, std::size_t n) {
|
||||
const int mul = getMul(div_);
|
||||
unsigned long sm1 = sum1;
|
||||
unsigned long sm2 = sum2;
|
||||
unsigned long sm3 = sum3;
|
||||
|
||||
while (n--) {
|
||||
{
|
||||
unsigned sn = div_ >> 1;
|
||||
|
||||
do {
|
||||
unsigned long s1 = sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
unsigned long s2 = sm2 += s1;
|
||||
sm2 += sm1;
|
||||
sm3 += s2;
|
||||
sm3 += sm2;
|
||||
} while (--sn);
|
||||
}
|
||||
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm2 += sm1;
|
||||
sm3 += sm2;
|
||||
|
||||
const unsigned long out3 = sm3 - prev3;
|
||||
prev3 = sm3;
|
||||
const unsigned long out2 = out3 - prev2;
|
||||
prev2 = out3;
|
||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
||||
prev1 = out2;
|
||||
out += channels;
|
||||
}
|
||||
|
||||
sum1 = sm1;
|
||||
sum2 = sm2;
|
||||
sum3 = sm3;
|
||||
}
|
||||
|
||||
template<unsigned channels>
|
||||
std::size_t Cic3EvenOddCore<channels>::filter(short *out, const short *const in, std::size_t inlen) {
|
||||
short *const outStart = out;
|
||||
const short *s = in;
|
||||
|
||||
if (inlen >= nextdivn) {
|
||||
{
|
||||
{
|
||||
unsigned divn = nextdivn;
|
||||
|
||||
do {
|
||||
sum1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sum2 += sum1;
|
||||
sum3 += sum2;
|
||||
} while (--divn);
|
||||
}
|
||||
|
||||
const unsigned long out3 = sum3 - prev3;
|
||||
prev3 = sum3;
|
||||
const unsigned long out2 = out3 - prev2;
|
||||
prev2 = out3;
|
||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * getMul(div_));
|
||||
prev1 = out2;
|
||||
out += channels;
|
||||
}
|
||||
|
||||
std::size_t n = (inlen - nextdivn) / div_;
|
||||
|
||||
if (div_ & 1)
|
||||
filterOdd(out, s, n);
|
||||
else
|
||||
filterEven(out, s, n);
|
||||
|
||||
s += n * div_ * channels;
|
||||
out += n * channels;
|
||||
nextdivn = div_;
|
||||
}
|
||||
|
||||
{
|
||||
unsigned divn = inlen - (s - in) / channels;
|
||||
nextdivn -= divn;
|
||||
|
||||
while (divn--) {
|
||||
sum1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sum2 += sum1;
|
||||
sum3 += sum2;
|
||||
}
|
||||
}
|
||||
|
||||
return (out - outStart) / channels;
|
||||
}*/
|
||||
|
||||
template<unsigned channels>
|
||||
class Cic3 : public SubResampler {
|
||||
Cic3Core<channels> cics[channels];
|
||||
|
||||
public:
|
||||
enum { MAX_DIV = 23 };
|
||||
explicit Cic3(unsigned div);
|
||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
||||
unsigned mul() const { return 1; }
|
||||
unsigned div() const { return cics[0].div(); }
|
||||
static double gain(unsigned div) { return Cic3Core<channels>::gain(div); }
|
||||
};
|
||||
|
||||
template<unsigned channels>
|
||||
Cic3<channels>::Cic3(const unsigned div) {
|
||||
for (unsigned i = 0; i < channels; ++i)
|
||||
cics[i].reset(div);
|
||||
}
|
||||
|
||||
template<unsigned channels>
|
||||
std::size_t Cic3<channels>::resample(short *const out, const short *const in, const std::size_t inlen) {
|
||||
std::size_t samplesOut;
|
||||
|
||||
for (unsigned i = 0; i < channels; ++i) {
|
||||
samplesOut = cics[i].filter(out + i, in + i, inlen);
|
||||
}
|
||||
|
||||
return samplesOut;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,246 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef CIC4_H
|
||||
#define CIC4_H
|
||||
|
||||
#include "subresampler.h"
|
||||
#include "rshift16_round.h"
|
||||
|
||||
template<unsigned channels>
|
||||
class Cic4Core {
|
||||
enum { BUFLEN = 64 };
|
||||
unsigned long buf[BUFLEN];
|
||||
unsigned long sum1;
|
||||
unsigned long sum2;
|
||||
unsigned long sum3;
|
||||
unsigned long sum4;
|
||||
unsigned long prev1;
|
||||
unsigned long prev2;
|
||||
unsigned long prev3;
|
||||
unsigned long prev4;
|
||||
unsigned div_;
|
||||
// unsigned nextdivn;
|
||||
unsigned bufpos;
|
||||
|
||||
// trouble if div is too large, may be better to only support power of 2 div
|
||||
static long mulForDiv(unsigned div) { return 0x10000 / (div * div * div * div); }
|
||||
|
||||
public:
|
||||
explicit Cic4Core(const unsigned div = 1) { reset(div); }
|
||||
unsigned div() const { return div_; }
|
||||
std::size_t filter(short *out, const short *in, std::size_t inlen);
|
||||
void reset(unsigned div);
|
||||
static double gain(unsigned div) { return rshift16_round(-32768l * (div * div * div * div) * mulForDiv(div)) / -32768.0; }
|
||||
};
|
||||
|
||||
template<unsigned channels>
|
||||
void Cic4Core<channels>::reset(const unsigned div) {
|
||||
sum4 = sum3 = sum2 = sum1 = 0;
|
||||
prev4 = prev3 = prev2 = prev1 = 0;
|
||||
this->div_ = div;
|
||||
// nextdivn = div;
|
||||
bufpos = div - 1;
|
||||
}
|
||||
|
||||
template<unsigned channels>
|
||||
std::size_t Cic4Core<channels>::filter(short *out, const short *const in, std::size_t inlen) {
|
||||
const std::size_t produced = (inlen + div_ - (bufpos + 1)) / div_;
|
||||
// const std::size_t produced = (inlen + div_ - nextdivn) / div_;
|
||||
const long mul = mulForDiv(div_);
|
||||
const short *s = in;
|
||||
|
||||
unsigned long sm1 = sum1;
|
||||
unsigned long sm2 = sum2;
|
||||
unsigned long sm3 = sum3;
|
||||
unsigned long sm4 = sum4;
|
||||
unsigned long prv1 = prev1;
|
||||
unsigned long prv2 = prev2;
|
||||
unsigned long prv3 = prev3;
|
||||
unsigned long prv4 = prev4;
|
||||
|
||||
while (inlen >> 2) {
|
||||
const unsigned end = inlen < BUFLEN ? inlen & ~3 : BUFLEN & ~3;
|
||||
unsigned long *b = buf;
|
||||
unsigned n = end;
|
||||
|
||||
do {
|
||||
unsigned long s1 = sm1 += static_cast<long>(s[0 * channels]);
|
||||
sm1 += static_cast<long>(s[1 * channels]);
|
||||
unsigned long s2 = sm2 += s1;
|
||||
sm2 += sm1;
|
||||
unsigned long s3 = sm3 += s2;
|
||||
sm3 += sm2;
|
||||
b[0] = sm4 += s3;
|
||||
b[1] = sm4 += sm3;
|
||||
s1 = sm1 += static_cast<long>(s[2 * channels]);
|
||||
sm1 += static_cast<long>(s[3 * channels]);
|
||||
s2 = sm2 += s1;
|
||||
sm2 += sm1;
|
||||
s3 = sm3 += s2;
|
||||
sm3 += sm2;
|
||||
b[2] = sm4 += s3;
|
||||
b[3] = sm4 += sm3;
|
||||
s += 4 * channels;
|
||||
b += 4;
|
||||
} while (n -= 4);
|
||||
|
||||
while (bufpos < end) {
|
||||
const unsigned long out4 = buf[bufpos] - prv4;
|
||||
prv4 = buf[bufpos];
|
||||
bufpos += div_;
|
||||
|
||||
const unsigned long out3 = out4 - prv3;
|
||||
prv3 = out4;
|
||||
const unsigned long out2 = out3 - prv2;
|
||||
prv2 = out3;
|
||||
|
||||
*out = rshift16_round(static_cast<long>(out2 - prv1) * mul);
|
||||
prv1 = out2;
|
||||
out += channels;
|
||||
}
|
||||
|
||||
bufpos -= end;
|
||||
inlen -= end;
|
||||
}
|
||||
|
||||
if (inlen) {
|
||||
unsigned n = inlen;
|
||||
unsigned i = 0;
|
||||
|
||||
do {
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm2 += sm1;
|
||||
sm3 += sm2;
|
||||
buf[i++] = sm4 += sm3;
|
||||
} while (--n);
|
||||
|
||||
while (bufpos < inlen) {
|
||||
const unsigned long out4 = buf[bufpos] - prv4;
|
||||
prv4 = buf[bufpos];
|
||||
bufpos += div_;
|
||||
|
||||
const unsigned long out3 = out4 - prv3;
|
||||
prv3 = out4;
|
||||
const unsigned long out2 = out3 - prv2;
|
||||
prv2 = out3;
|
||||
|
||||
*out = rshift16_round(static_cast<long>(out2 - prv1) * mul);
|
||||
prv1 = out2;
|
||||
out += channels;
|
||||
}
|
||||
|
||||
bufpos -= inlen;
|
||||
}
|
||||
|
||||
sum1 = sm1;
|
||||
sum2 = sm2;
|
||||
sum3 = sm3;
|
||||
sum4 = sm4;
|
||||
prev1 = prv1;
|
||||
prev2 = prv2;
|
||||
prev3 = prv3;
|
||||
prev4 = prv4;
|
||||
|
||||
/*unsigned long sm1 = sum1;
|
||||
unsigned long sm2 = sum2;
|
||||
unsigned long sm3 = sum3;
|
||||
unsigned long sm4 = sum4;
|
||||
|
||||
if (produced) {
|
||||
unsigned divn = nextdivn;
|
||||
std::size_t n = produced;
|
||||
|
||||
do {
|
||||
do {
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm2 += sm1;
|
||||
sm3 += sm2;
|
||||
sm4 += sm3;
|
||||
} while (--divn);
|
||||
|
||||
const unsigned long out4 = sm4 - prev4;
|
||||
prev4 = sm4;
|
||||
const unsigned long out3 = out4 - prev3;
|
||||
prev3 = out4;
|
||||
const unsigned long out2 = out3 - prev2;
|
||||
prev2 = out3;
|
||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
||||
prev1 = out2;
|
||||
out += channels;
|
||||
|
||||
divn = div_;
|
||||
} while (--n);
|
||||
|
||||
nextdivn = div_;
|
||||
}
|
||||
|
||||
{
|
||||
unsigned divn = (in + inlen * channels - s) / channels;
|
||||
nextdivn -= divn;
|
||||
|
||||
while (divn--) {
|
||||
sm1 += static_cast<long>(*s);
|
||||
s += channels;
|
||||
sm2 += sm1;
|
||||
sm3 += sm2;
|
||||
sm4 += sm3;
|
||||
}
|
||||
}
|
||||
|
||||
sum1 = sm1;
|
||||
sum2 = sm2;
|
||||
sum3 = sm3;
|
||||
sum4 = sm4;*/
|
||||
|
||||
return produced;
|
||||
}
|
||||
|
||||
template<unsigned channels>
|
||||
class Cic4 : public SubResampler {
|
||||
Cic4Core<channels> cics[channels];
|
||||
|
||||
public:
|
||||
enum { MAX_DIV = 13 };
|
||||
explicit Cic4(unsigned div);
|
||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
||||
unsigned mul() const { return 1; }
|
||||
unsigned div() const { return cics[0].div(); }
|
||||
static double gain(unsigned div) { return Cic4Core<channels>::gain(div); }
|
||||
};
|
||||
|
||||
template<unsigned channels>
|
||||
Cic4<channels>::Cic4(const unsigned div) {
|
||||
for (unsigned i = 0; i < channels; ++i)
|
||||
cics[i].reset(div);
|
||||
}
|
||||
|
||||
template<unsigned channels>
|
||||
std::size_t Cic4<channels>::resample(short *const out, const short *const in, const std::size_t inlen) {
|
||||
std::size_t samplesOut;
|
||||
|
||||
for (unsigned i = 0; i < channels; ++i) {
|
||||
samplesOut = cics[i].filter(out + i, in + i, inlen);
|
||||
}
|
||||
|
||||
return samplesOut;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,112 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef RINGBUFFER_H
|
||||
#define RINGBUFFER_H
|
||||
|
||||
#include "array.h"
|
||||
#include <cstddef>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
template<typename T>
|
||||
class RingBuffer {
|
||||
Array<T> buf;
|
||||
std::size_t sz;
|
||||
std::size_t rpos;
|
||||
std::size_t wpos;
|
||||
|
||||
public:
|
||||
explicit RingBuffer(const std::size_t sz_in = 0) : sz(0), rpos(0), wpos(0) { reset(sz_in); }
|
||||
|
||||
std::size_t avail() const {
|
||||
return (wpos < rpos ? 0 : sz) + rpos - wpos - 1;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
wpos = rpos = 0;
|
||||
}
|
||||
|
||||
void fill(T value);
|
||||
|
||||
void read(T *out, std::size_t num);
|
||||
|
||||
void reset(std::size_t sz_in);
|
||||
|
||||
std::size_t size() const {
|
||||
return sz - 1;
|
||||
}
|
||||
|
||||
std::size_t used() const {
|
||||
return (wpos < rpos ? sz : 0) + wpos - rpos;
|
||||
}
|
||||
|
||||
void write(const T *in, std::size_t num);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void RingBuffer<T>::fill(const T value) {
|
||||
std::fill(buf + 0, buf + sz, value);
|
||||
rpos = 0;
|
||||
wpos = sz - 1;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RingBuffer<T>::read(T *out, std::size_t num) {
|
||||
if (rpos + num > sz) {
|
||||
const std::size_t n = sz - rpos;
|
||||
|
||||
std::memcpy(out, buf + rpos, n * sizeof(T));
|
||||
|
||||
rpos = 0;
|
||||
num -= n;
|
||||
out += n;
|
||||
}
|
||||
|
||||
std::memcpy(out, buf + rpos, num * sizeof(T));
|
||||
|
||||
if ((rpos += num) == sz)
|
||||
rpos = 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RingBuffer<T>::reset(const std::size_t sz_in) {
|
||||
sz = sz_in + 1;
|
||||
rpos = wpos = 0;
|
||||
buf.reset(sz_in ? sz : 0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RingBuffer<T>::write(const T *in, std::size_t num) {
|
||||
if (wpos + num > sz) {
|
||||
const std::size_t n = sz - wpos;
|
||||
|
||||
std::memcpy(buf + wpos, in, n * sizeof(T));
|
||||
|
||||
wpos = 0;
|
||||
num -= n;
|
||||
in += n;
|
||||
}
|
||||
|
||||
std::memcpy(buf + wpos, in, num * sizeof(T));
|
||||
|
||||
if ((wpos += num) == sz)
|
||||
wpos = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,35 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "skipsched.h"
|
||||
|
||||
bool SkipSched::skipNext(bool skip) {
|
||||
if (skipped) {
|
||||
if (skipped < skippedmax / 2)
|
||||
skip = true;
|
||||
else
|
||||
skipped = skip = 0;
|
||||
} else if (skip) {
|
||||
skippedmax += skippedmax / 2 < 8;
|
||||
} else if (skippedmax / 2)
|
||||
--skippedmax;
|
||||
|
||||
skipped += skip;
|
||||
|
||||
return skip;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SKIPSCHED_H
|
||||
#define SKIPSCHED_H
|
||||
|
||||
class SkipSched {
|
||||
unsigned skipped;
|
||||
unsigned skippedmax;
|
||||
|
||||
public:
|
||||
SkipSched() { reset(); }
|
||||
|
||||
void reset() {
|
||||
skipped = 0;
|
||||
skippedmax = 2 - 1;
|
||||
}
|
||||
|
||||
bool skipNext(bool wantskip);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,31 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef USEC_H
|
||||
#define USEC_H
|
||||
|
||||
typedef unsigned long usec_t;
|
||||
|
||||
static inline usec_t negate(usec_t t) {
|
||||
return usec_t(0) - t;
|
||||
}
|
||||
|
||||
usec_t getusecs();
|
||||
void usecsleep(usec_t usecs);
|
||||
|
||||
#endif
|
||||
@@ -1,158 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "rgb32conv.h"
|
||||
#include "videolink.h"
|
||||
#include "array.h"
|
||||
#include "gbint.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
class Rgb32ToUyvy {
|
||||
struct CacheUnit {
|
||||
gambatte::uint_least32_t rgb32;
|
||||
gambatte::uint_least32_t uyvy;
|
||||
};
|
||||
|
||||
enum { cache_size = 0x100 };
|
||||
enum { cache_mask = cache_size - 1 };
|
||||
|
||||
CacheUnit cache[cache_size];
|
||||
|
||||
public:
|
||||
Rgb32ToUyvy();
|
||||
void operator()(const gambatte::uint_least32_t *s, gambatte::uint_least32_t *d,
|
||||
unsigned w, unsigned h, int srcPitch, int dstPitch);
|
||||
};
|
||||
|
||||
Rgb32ToUyvy::Rgb32ToUyvy() {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
const CacheUnit c = { 0, 128ul << 24 | 16ul << 16 | 128 << 8 | 16 };
|
||||
#else
|
||||
const CacheUnit c = { 0, 16ul << 24 | 128ul << 16 | 16 << 8 | 128 };
|
||||
#endif
|
||||
std::fill(cache, cache + cache_size, c);
|
||||
}
|
||||
|
||||
void Rgb32ToUyvy::operator()(const gambatte::uint_least32_t *s,
|
||||
gambatte::uint_least32_t *d, const unsigned w, unsigned h, const int s_pitch, const int d_pitch)
|
||||
{
|
||||
while (h--) {
|
||||
unsigned n = w >> 1;
|
||||
|
||||
do {
|
||||
if ((cache[*s & cache_mask].rgb32 - *s) | (cache[*(s+1) & cache_mask].rgb32 - *(s+1))) {
|
||||
cache[*s & cache_mask].rgb32 = *s;
|
||||
cache[*(s+1) & cache_mask].rgb32 = *(s+1);
|
||||
|
||||
const unsigned long r = (*s >> 16 & 0x000000FF) | (*(s+1) & 0x00FF0000);
|
||||
const unsigned long g = (*s >> 8 & 0x000000FF) | (*(s+1) << 8 & 0x00FF0000);
|
||||
const unsigned long b = (*s & 0x000000FF) | (*(s+1) << 16 & 0x00FF0000);
|
||||
|
||||
const unsigned long y = r * 66 + g * 129 + b * 25 + ( 16 * 256 + 128) * 0x00010001ul;
|
||||
const unsigned long u = b * 112 - r * 38 - g * 74 + (128 * 256 + 128) * 0x00010001ul;
|
||||
const unsigned long v = r * 112 - g * 94 - b * 18 + (128 * 256 + 128) * 0x00010001ul;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
cache[*s & cache_mask].uyvy = (u << 16 & 0xFF000000) | (y << 8 & 0x00FF0000) | (v & 0x0000FF00) | (y >> 8 & 0x000000FF);
|
||||
cache[*(s+1) & cache_mask].uyvy = (u & 0xFF000000) | (y >> 8 & 0x00FF0000) | (v >> 16 & 0x0000FF00) | y >> 24;
|
||||
#else
|
||||
cache[*s & cache_mask].uyvy = (y << 16 & 0xFF000000) | (v << 8 & 0x00FF0000) | (y & 0x0000FF00) | (u >> 8 & 0x000000FF);
|
||||
cache[*(s+1) & cache_mask].uyvy = (y & 0xFF000000) | (v >> 8 & 0x00FF0000) | (y >> 16 & 0x0000FF00) | u >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
*d = cache[*s & cache_mask].uyvy;
|
||||
*(d+1) = cache[*(s+1) & cache_mask].uyvy;
|
||||
s += 2;
|
||||
d += 2;
|
||||
} while (--n);
|
||||
|
||||
s += s_pitch - static_cast<int>(w);
|
||||
d += d_pitch - static_cast<int>(w);
|
||||
}
|
||||
}
|
||||
|
||||
static void rgb32ToRgb16(const gambatte::uint_least32_t *s, gambatte::uint_least16_t *d,
|
||||
const unsigned w, unsigned h, const int srcPitch, const int dstPitch)
|
||||
{
|
||||
do {
|
||||
int i = -static_cast<int>(w);
|
||||
s += w;
|
||||
d += w;
|
||||
|
||||
do {
|
||||
d[i] = (s[i] >> 8 & 0xF800) | (s[i] & 0xFC00) >> 5 | (s[i] & 0xFF) >> 3;
|
||||
} while (++i);
|
||||
|
||||
s += srcPitch - static_cast<int>(w);
|
||||
d += dstPitch - static_cast<int>(w);
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
class Rgb32ToUyvyLink : public VideoLink {
|
||||
const Array<gambatte::uint_least32_t> inbuf_;
|
||||
Rgb32ToUyvy rgb32ToUyvy;
|
||||
const unsigned width_;
|
||||
const unsigned height_;
|
||||
|
||||
public:
|
||||
Rgb32ToUyvyLink(unsigned width, unsigned height)
|
||||
: inbuf_(static_cast<std::size_t>(width) * height),
|
||||
width_(width),
|
||||
height_(height)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void* inBuf() const { return inbuf_; }
|
||||
virtual int inPitch() const { return width_; }
|
||||
|
||||
virtual void draw(void *dst, int dstpitch) {
|
||||
rgb32ToUyvy(inbuf_, static_cast<gambatte::uint_least32_t*>(dst), width_, height_, inPitch(), dstpitch);
|
||||
}
|
||||
};
|
||||
|
||||
class Rgb32ToRgb16Link : public VideoLink {
|
||||
const Array<gambatte::uint_least32_t> inbuf_;
|
||||
const unsigned width_;
|
||||
const unsigned height_;
|
||||
|
||||
public:
|
||||
Rgb32ToRgb16Link(unsigned width, unsigned height)
|
||||
: inbuf_(static_cast<std::size_t>(width) * height),
|
||||
width_(width),
|
||||
height_(height)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void* inBuf() const { return inbuf_; }
|
||||
virtual int inPitch() const { return width_; }
|
||||
|
||||
virtual void draw(void *dst, int dstpitch) {
|
||||
rgb32ToRgb16(inbuf_, static_cast<gambatte::uint_least16_t*>(dst), width_, height_, inPitch(), dstpitch);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
VideoLink* Rgb32Conv::create(PixelFormat pf, unsigned width, unsigned height) {
|
||||
switch (pf) {
|
||||
case RGB16: return new Rgb32ToRgb16Link(width, height);
|
||||
case UYVY: return new Rgb32ToUyvyLink(width, height);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef RGB32CONV_H
|
||||
#define RGB32CONV_H
|
||||
|
||||
class VideoLink;
|
||||
|
||||
class Rgb32Conv {
|
||||
public:
|
||||
enum PixelFormat { RGB32, RGB16, UYVY };
|
||||
static VideoLink* create(PixelFormat pf, unsigned width, unsigned height);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,48 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "vfilterinfo.h"
|
||||
#include "vfilters/catrom2x.h"
|
||||
#include "vfilters/catrom3x.h"
|
||||
#include "vfilters/kreed2xsai.h"
|
||||
#include "vfilters/maxsthq2x.h"
|
||||
#include "vfilters/maxsthq3x.h"
|
||||
|
||||
static VideoLink* createNone() { return 0; }
|
||||
|
||||
template<class T>
|
||||
static VideoLink* createT() { return new T; }
|
||||
|
||||
#define VFINFO(handle, Type) { handle, Type::OUT_WIDTH, Type::OUT_HEIGHT, createT<Type> }
|
||||
|
||||
static const VfilterInfo vfinfos[] = {
|
||||
{ "None", VfilterInfo::IN_WIDTH, VfilterInfo::IN_HEIGHT, createNone },
|
||||
VFINFO("Bicubic Catmull-Rom spline 2x", Catrom2x),
|
||||
VFINFO("Bicubic Catmull-Rom spline 3x", Catrom3x),
|
||||
VFINFO("Kreed's 2xSaI", Kreed2xSaI),
|
||||
VFINFO("MaxSt's hq2x", MaxStHq2x),
|
||||
VFINFO("MaxSt's hq3x", MaxStHq3x)
|
||||
};
|
||||
|
||||
std::size_t VfilterInfo::numVfilters() {
|
||||
return sizeof(vfinfos) / sizeof(vfinfos[0]);
|
||||
}
|
||||
|
||||
const VfilterInfo& VfilterInfo::get(std::size_t n) {
|
||||
return vfinfos[n];
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef VFILTERINFO_H
|
||||
#define VFILTERINFO_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
class VideoLink;
|
||||
|
||||
struct VfilterInfo {
|
||||
enum { IN_WIDTH = 160 };
|
||||
enum { IN_HEIGHT = 144 };
|
||||
|
||||
const char *handle;
|
||||
unsigned outWidth;
|
||||
unsigned outHeight;
|
||||
VideoLink* (*create)();
|
||||
|
||||
static const VfilterInfo& get(std::size_t n);
|
||||
static std::size_t numVfilters();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,179 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "catrom2x.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
enum { WIDTH = VfilterInfo::IN_WIDTH };
|
||||
enum { HEIGHT = VfilterInfo::IN_HEIGHT };
|
||||
enum { PITCH = WIDTH + 3 };
|
||||
|
||||
struct Colorsum {
|
||||
gambatte::uint_least32_t r, g, b;
|
||||
};
|
||||
|
||||
static void merge_columns(gambatte::uint_least32_t *dest, const Colorsum *sums) {
|
||||
unsigned w = WIDTH;
|
||||
|
||||
while (w--) {
|
||||
{
|
||||
gambatte::uint_least32_t rsum = sums[1].r;
|
||||
gambatte::uint_least32_t gsum = sums[1].g;
|
||||
gambatte::uint_least32_t bsum = sums[1].b;
|
||||
|
||||
if (rsum & 0x80000000) rsum = 0;
|
||||
if (gsum & 0x80000000) gsum = 0;
|
||||
if (bsum & 0x80000000) bsum = 0;
|
||||
|
||||
rsum <<= 12;
|
||||
rsum += 0x008000;
|
||||
gsum >>= 4;
|
||||
gsum += 0x0080;
|
||||
bsum += 0x0008;
|
||||
bsum >>= 4;
|
||||
|
||||
if (rsum > 0xFF0000) rsum = 0xFF0000;
|
||||
if (gsum > 0x00FF00) gsum = 0x00FF00;
|
||||
if (bsum > 0x0000FF) bsum = 0x0000FF;
|
||||
|
||||
*dest++ = (rsum & 0xFF0000) | (gsum & 0x00FF00) | bsum;
|
||||
}
|
||||
|
||||
{
|
||||
gambatte::uint_least32_t rsum = sums[1].r * 9;
|
||||
gambatte::uint_least32_t gsum = sums[1].g * 9;
|
||||
gambatte::uint_least32_t bsum = sums[1].b * 9;
|
||||
|
||||
rsum -= sums[0].r;
|
||||
gsum -= sums[0].g;
|
||||
bsum -= sums[0].b;
|
||||
|
||||
rsum += sums[2].r * 9;
|
||||
gsum += sums[2].g * 9;
|
||||
bsum += sums[2].b * 9;
|
||||
|
||||
rsum -= sums[3].r;
|
||||
gsum -= sums[3].g;
|
||||
bsum -= sums[3].b;
|
||||
|
||||
if (rsum & 0x80000000) rsum = 0;
|
||||
if (gsum & 0x80000000) gsum = 0;
|
||||
if (bsum & 0x80000000) bsum = 0;
|
||||
|
||||
rsum <<= 8;
|
||||
rsum += 0x008000;
|
||||
gsum >>= 8;
|
||||
gsum += 0x000080;
|
||||
bsum += 0x000080;
|
||||
bsum >>= 8;
|
||||
|
||||
if (rsum > 0xFF0000) rsum = 0xFF0000;
|
||||
if (gsum > 0x00FF00) gsum = 0x00FF00;
|
||||
if (bsum > 0x0000FF) bsum = 0x0000FF;
|
||||
|
||||
*dest++ = (rsum & 0xFF0000) | (gsum & 0x00FF00) | bsum;
|
||||
}
|
||||
|
||||
++sums;
|
||||
}
|
||||
}
|
||||
|
||||
static void filter(gambatte::uint_least32_t *dline, const int pitch, const gambatte::uint_least32_t *sline) {
|
||||
Colorsum sums[PITCH];
|
||||
|
||||
for (unsigned h = HEIGHT; h--;) {
|
||||
{
|
||||
const gambatte::uint_least32_t *s = sline;
|
||||
Colorsum *sum = sums;
|
||||
unsigned n = PITCH;
|
||||
|
||||
while (n--) {
|
||||
unsigned long pixel = *s;
|
||||
sum->r = pixel >> 12 & 0x000FF0 ;
|
||||
pixel <<= 4;
|
||||
sum->g = pixel & 0x0FF000;
|
||||
sum->b = pixel & 0x000FF0;
|
||||
|
||||
++s;
|
||||
++sum;
|
||||
}
|
||||
}
|
||||
|
||||
merge_columns(dline, sums);
|
||||
dline += pitch;
|
||||
|
||||
{
|
||||
const gambatte::uint_least32_t *s = sline;
|
||||
Colorsum *sum = sums;
|
||||
unsigned n = PITCH;
|
||||
|
||||
while (n--) {
|
||||
unsigned long pixel = *s;
|
||||
unsigned long rsum = (pixel >> 16) * 9;
|
||||
unsigned long gsum = (pixel & 0x00FF00) * 9;
|
||||
unsigned long bsum = (pixel & 0x0000FF) * 9;
|
||||
|
||||
pixel = s[-1*PITCH];
|
||||
rsum -= pixel >> 16;
|
||||
gsum -= pixel & 0x00FF00;
|
||||
bsum -= pixel & 0x0000FF;
|
||||
|
||||
pixel = s[1*PITCH];
|
||||
rsum += (pixel >> 16) * 9;
|
||||
gsum += (pixel & 0x00FF00) * 9;
|
||||
bsum += (pixel & 0x0000FF) * 9;
|
||||
|
||||
pixel = s[2*PITCH];
|
||||
rsum -= pixel >> 16;
|
||||
gsum -= pixel & 0x00FF00;
|
||||
bsum -= pixel & 0x0000FF;
|
||||
|
||||
sum->r = rsum;
|
||||
sum->g = gsum;
|
||||
sum->b = bsum;
|
||||
|
||||
++s;
|
||||
++sum;
|
||||
}
|
||||
}
|
||||
|
||||
merge_columns(dline, sums);
|
||||
dline += pitch;
|
||||
sline += PITCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Catrom2x::Catrom2x()
|
||||
: buffer_((HEIGHT + 3UL) * PITCH)
|
||||
{
|
||||
std::fill_n(buffer_.get(), buffer_.size(), 0);
|
||||
}
|
||||
|
||||
void* Catrom2x::inBuf() const {
|
||||
return buffer_ + PITCH + 1;
|
||||
}
|
||||
|
||||
int Catrom2x::inPitch() const {
|
||||
return PITCH;
|
||||
}
|
||||
|
||||
void Catrom2x::draw(void *const dbuffer, const int pitch) {
|
||||
::filter(static_cast<gambatte::uint_least32_t*>(dbuffer), pitch, buffer_ + PITCH);
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef CATROM2X_H
|
||||
#define CATROM2X_H
|
||||
|
||||
#include "../videolink.h"
|
||||
#include "../vfilterinfo.h"
|
||||
#include "array.h"
|
||||
#include "gbint.h"
|
||||
|
||||
class Catrom2x : public VideoLink {
|
||||
const Array<gambatte::uint_least32_t> buffer_;
|
||||
public:
|
||||
enum { OUT_WIDTH = VfilterInfo::IN_WIDTH * 2 };
|
||||
enum { OUT_HEIGHT = VfilterInfo::IN_HEIGHT * 2 };
|
||||
|
||||
Catrom2x();
|
||||
virtual void* inBuf() const;
|
||||
virtual int inPitch() const;
|
||||
virtual void draw(void *dst, int dstpitch);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,345 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "catrom3x.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
enum { WIDTH = VfilterInfo::IN_WIDTH };
|
||||
enum { HEIGHT = VfilterInfo::IN_HEIGHT };
|
||||
enum { PITCH = WIDTH + 3 };
|
||||
|
||||
struct Colorsum {
|
||||
gambatte::uint_least32_t r, g, b;
|
||||
};
|
||||
|
||||
static void merge_columns(gambatte::uint_least32_t *dest, const Colorsum *sums) {
|
||||
unsigned w = WIDTH;
|
||||
|
||||
while (w--) {
|
||||
{
|
||||
gambatte::uint_least32_t rsum = sums[1].r;
|
||||
gambatte::uint_least32_t gsum = sums[1].g;
|
||||
gambatte::uint_least32_t bsum = sums[1].b;
|
||||
|
||||
if (rsum & 0x80000000)
|
||||
rsum = 0;
|
||||
else if (rsum > 6869)
|
||||
rsum = 0xFF0000;
|
||||
else {
|
||||
rsum *= 607;
|
||||
rsum <<= 2;
|
||||
rsum += 0x008000;
|
||||
rsum &= 0xFF0000;
|
||||
}
|
||||
|
||||
if (gsum & 0x80000000)
|
||||
gsum = 0;
|
||||
else if (gsum > 1758567)
|
||||
gsum = 0xFF00;
|
||||
else {
|
||||
gsum *= 607;
|
||||
gsum >>= 14;
|
||||
gsum += 0x000080;
|
||||
gsum &= 0x00FF00;
|
||||
}
|
||||
|
||||
if (bsum & 0x80000000)
|
||||
bsum = 0;
|
||||
else if (bsum > 6869)
|
||||
bsum = 0xFF;
|
||||
else {
|
||||
bsum *= 607;
|
||||
bsum += 8192;
|
||||
bsum >>= 14;
|
||||
}
|
||||
|
||||
/*rsum/=27;
|
||||
rsum<<=8;
|
||||
gsum/=27;
|
||||
gsum<<=5;
|
||||
bsum<<=4;
|
||||
bsum+=27;
|
||||
bsum/=54;
|
||||
rsum+=0x008000;
|
||||
gsum+=0x000080;
|
||||
|
||||
if(rsum>0xFF0000) rsum=0xFF0000;
|
||||
if(gsum>0x00FF00) gsum=0x00FF00;
|
||||
if(bsum>0x0000FF) bsum=0x0000FF;*/
|
||||
|
||||
*dest++ = rsum/*&0xFF0000*/ | gsum/*&0x00FF00*/ | bsum;
|
||||
}
|
||||
{
|
||||
gambatte::uint_least32_t rsum = sums[1].r * 21;
|
||||
gambatte::uint_least32_t gsum = sums[1].g * 21;
|
||||
gambatte::uint_least32_t bsum = sums[1].b * 21;
|
||||
|
||||
rsum -= sums[0].r << 1;
|
||||
gsum -= sums[0].g << 1;
|
||||
bsum -= sums[0].b << 1;
|
||||
|
||||
rsum += sums[2].r * 9;
|
||||
gsum += sums[2].g * 9;
|
||||
bsum += sums[2].b * 9;
|
||||
|
||||
rsum -= sums[3].r;
|
||||
gsum -= sums[3].g;
|
||||
bsum -= sums[3].b;
|
||||
|
||||
if (rsum & 0x80000000)
|
||||
rsum = 0;
|
||||
else if (rsum > 185578)
|
||||
rsum = 0xFF0000;
|
||||
else {
|
||||
rsum *= 719;
|
||||
rsum >>= 3;
|
||||
rsum += 0x008000;
|
||||
rsum &= 0xFF0000;
|
||||
}
|
||||
|
||||
if (gsum & 0x80000000)
|
||||
gsum = 0;
|
||||
else if (gsum > 47508223)
|
||||
gsum = 0x00FF00;
|
||||
else {
|
||||
gsum >>= 8;
|
||||
gsum *= 719;
|
||||
gsum >>= 11;
|
||||
gsum += 0x000080;
|
||||
gsum &= 0x00FF00;
|
||||
}
|
||||
|
||||
if (bsum & 0x80000000)
|
||||
bsum = 0;
|
||||
else if (bsum > 185578)
|
||||
bsum = 0x0000FF;
|
||||
else {
|
||||
bsum *= 719;
|
||||
bsum += 0x040000;
|
||||
bsum >>= 19;
|
||||
}
|
||||
|
||||
/*rsum/=729;
|
||||
rsum<<=8;
|
||||
gsum/=729;
|
||||
gsum<<=5;
|
||||
bsum<<=4;
|
||||
bsum+=729;
|
||||
bsum/=1458;
|
||||
rsum+=0x008000;
|
||||
gsum+=0x000080;
|
||||
|
||||
if(rsum>0xFF0000) rsum=0xFF0000;
|
||||
if(gsum>0x00FF00) gsum=0x00FF00;
|
||||
if(bsum>0x0000FF) bsum=0x0000FF;*/
|
||||
|
||||
*dest++ = rsum/*&0xFF0000*/ | gsum/*&0x00FF00*/ | bsum;
|
||||
}
|
||||
{
|
||||
gambatte::uint_least32_t rsum = sums[1].r * 9;
|
||||
gambatte::uint_least32_t gsum = sums[1].g * 9;
|
||||
gambatte::uint_least32_t bsum = sums[1].b * 9;
|
||||
|
||||
rsum -= sums[0].r;
|
||||
gsum -= sums[0].g;
|
||||
bsum -= sums[0].b;
|
||||
|
||||
rsum += sums[2].r * 21;
|
||||
gsum += sums[2].g * 21;
|
||||
bsum += sums[2].b * 21;
|
||||
|
||||
rsum -= sums[3].r << 1;
|
||||
gsum -= sums[3].g << 1;
|
||||
bsum -= sums[3].b << 1;
|
||||
|
||||
if (rsum & 0x80000000)
|
||||
rsum = 0;
|
||||
else if (rsum > 185578)
|
||||
rsum = 0xFF0000;
|
||||
else {
|
||||
rsum *= 719;
|
||||
rsum >>= 3;
|
||||
rsum += 0x008000;
|
||||
rsum &= 0xFF0000;
|
||||
}
|
||||
|
||||
if (gsum & 0x80000000)
|
||||
gsum = 0;
|
||||
else if (gsum > 47508223)
|
||||
gsum = 0xFF00;
|
||||
else {
|
||||
gsum >>= 8;
|
||||
gsum *= 719;
|
||||
gsum >>= 11;
|
||||
gsum += 0x000080;
|
||||
gsum &= 0x00FF00;
|
||||
}
|
||||
|
||||
if (bsum & 0x80000000)
|
||||
bsum = 0;
|
||||
else if (bsum > 185578)
|
||||
bsum = 0x0000FF;
|
||||
else {
|
||||
bsum *= 719;
|
||||
bsum += 0x040000;
|
||||
bsum >>= 19;
|
||||
}
|
||||
|
||||
/*rsum/=729;
|
||||
rsum<<=8;
|
||||
gsum/=729;
|
||||
gsum<<=5;
|
||||
bsum<<=4;
|
||||
bsum+=729;
|
||||
bsum/=1458;
|
||||
rsum+=0x008000;
|
||||
gsum+=0x000080;
|
||||
|
||||
if(rsum>0xFF0000) rsum=0xFF0000;
|
||||
if(gsum>0x00FF00) gsum=0x00FF00;
|
||||
if(bsum>0x0000FF) bsum=0x0000FF;*/
|
||||
|
||||
*dest++ = rsum/*&0xFF0000*/ | gsum/*&0x00FF00*/ | bsum;
|
||||
}
|
||||
++sums;
|
||||
}
|
||||
}
|
||||
|
||||
static void filter(gambatte::uint_least32_t *dline, const int pitch, const gambatte::uint_least32_t *sline) {
|
||||
Colorsum sums[PITCH];
|
||||
|
||||
for (unsigned h = HEIGHT; h--;) {
|
||||
{
|
||||
const gambatte::uint_least32_t *s = sline;
|
||||
Colorsum *sum = sums;
|
||||
unsigned n = PITCH;
|
||||
|
||||
while (n--) {
|
||||
const unsigned long pixel = *s;
|
||||
sum->r = (pixel >> 16) * 27;
|
||||
sum->g = (pixel & 0x00FF00) * 27;
|
||||
sum->b = (pixel & 0x0000FF) * 27;
|
||||
|
||||
++s;
|
||||
++sum;
|
||||
}
|
||||
}
|
||||
|
||||
merge_columns(dline, sums);
|
||||
dline += pitch;
|
||||
|
||||
{
|
||||
const gambatte::uint_least32_t *s = sline;
|
||||
Colorsum *sum = sums;
|
||||
unsigned n = PITCH;
|
||||
|
||||
while (n--) {
|
||||
unsigned long pixel = *s;
|
||||
unsigned long rsum = (pixel >> 16) * 21;
|
||||
unsigned long gsum = (pixel & 0x00FF00) * 21;
|
||||
unsigned long bsum = (pixel & 0x0000FF) * 21;
|
||||
|
||||
pixel = s[-1 * PITCH];
|
||||
rsum -= (pixel >> 16) << 1;
|
||||
pixel <<= 1;
|
||||
gsum -= pixel & 0x01FE00;
|
||||
bsum -= pixel & 0x0001FE;
|
||||
|
||||
pixel = s[1 * PITCH];
|
||||
rsum += (pixel >> 16) * 9;
|
||||
gsum += (pixel & 0x00FF00) * 9;
|
||||
bsum += (pixel & 0x0000FF) * 9;
|
||||
|
||||
pixel = s[2 * PITCH];
|
||||
rsum -= pixel >> 16;
|
||||
gsum -= pixel & 0x00FF00;
|
||||
bsum -= pixel & 0x0000FF;
|
||||
|
||||
sum->r = rsum;
|
||||
sum->g = gsum;
|
||||
sum->b = bsum;
|
||||
|
||||
++s;
|
||||
++sum;
|
||||
}
|
||||
}
|
||||
|
||||
merge_columns(dline, sums);
|
||||
dline += pitch;
|
||||
|
||||
{
|
||||
const gambatte::uint_least32_t *s = sline;
|
||||
Colorsum *sum = sums;
|
||||
unsigned n = PITCH;
|
||||
|
||||
while (n--) {
|
||||
unsigned long pixel = *s;
|
||||
unsigned long rsum = (pixel >> 16) * 9;
|
||||
unsigned long gsum = (pixel & 0x00FF00) * 9;
|
||||
unsigned long bsum = (pixel & 0x0000FF) * 9;
|
||||
|
||||
pixel = s[-1 * PITCH];
|
||||
rsum -= pixel >> 16;
|
||||
gsum -= pixel & 0x00FF00;
|
||||
bsum -= pixel & 0x0000FF;
|
||||
|
||||
pixel = s[1 * PITCH];
|
||||
rsum += (pixel >> 16) * 21;
|
||||
gsum += (pixel & 0x00FF00) * 21;
|
||||
bsum += (pixel & 0x0000FF) * 21;
|
||||
|
||||
pixel = s[2 * PITCH];
|
||||
rsum -= (pixel >> 16) << 1;
|
||||
pixel <<= 1;
|
||||
gsum -= pixel & 0x01FE00;
|
||||
bsum -= pixel & 0x0001FE;
|
||||
|
||||
sum->r = rsum;
|
||||
sum->g = gsum;
|
||||
sum->b = bsum;
|
||||
|
||||
++s;
|
||||
++sum;
|
||||
}
|
||||
}
|
||||
|
||||
merge_columns(dline, sums);
|
||||
dline += pitch;
|
||||
sline += PITCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Catrom3x::Catrom3x()
|
||||
: buffer_((HEIGHT + 3UL) * PITCH)
|
||||
{
|
||||
std::fill_n(buffer_.get(), buffer_.size(), 0);
|
||||
}
|
||||
|
||||
void* Catrom3x::inBuf() const {
|
||||
return buffer_ + PITCH + 1;
|
||||
}
|
||||
|
||||
int Catrom3x::inPitch() const {
|
||||
return PITCH;
|
||||
}
|
||||
|
||||
void Catrom3x::draw(void *const dbuffer, const int pitch) {
|
||||
::filter(static_cast<gambatte::uint_least32_t*>(dbuffer), pitch, buffer_ + PITCH);
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef CATROM3X_H
|
||||
#define CATROM3X_H
|
||||
|
||||
#include "../videolink.h"
|
||||
#include "../vfilterinfo.h"
|
||||
#include "array.h"
|
||||
#include "gbint.h"
|
||||
|
||||
class Catrom3x : public VideoLink {
|
||||
const Array<gambatte::uint_least32_t> buffer_;
|
||||
public:
|
||||
enum { OUT_WIDTH = VfilterInfo::IN_WIDTH * 3 };
|
||||
enum { OUT_HEIGHT = VfilterInfo::IN_HEIGHT * 3 };
|
||||
|
||||
Catrom3x();
|
||||
virtual void* inBuf() const;
|
||||
virtual int inPitch() const;
|
||||
virtual void draw(void *dst, int dstpitch);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,234 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* Copyright (C) 1999 Derek Liauw Kie Fa (Kreed) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "kreed2xsai.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
|
||||
static inline int getResult1(const unsigned long a, const unsigned long b, const unsigned long c, const unsigned long d) {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int r = 0;
|
||||
|
||||
if (a == c) ++x;
|
||||
else if (b == c) ++y;
|
||||
|
||||
if (a == d) ++x;
|
||||
else if (b == d) ++y;
|
||||
|
||||
if (x <= 1) ++r;
|
||||
|
||||
if (y <= 1) --r;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline int getResult2(const unsigned long a, const unsigned long b, const unsigned long c, const unsigned long d) {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int r = 0;
|
||||
|
||||
if (a == c) ++x;
|
||||
else if (b == c) ++y;
|
||||
|
||||
if (a == d) ++x;
|
||||
else if (b == d) ++y;
|
||||
|
||||
if (x <= 1) --r;
|
||||
|
||||
if (y <= 1) ++r;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline unsigned long interpolate(const unsigned long a, const unsigned long b) {
|
||||
return (a + b - ((a ^ b) & 0x010101)) >> 1;
|
||||
}
|
||||
|
||||
static inline unsigned long qInterpolate(const unsigned long a, const unsigned long b, const unsigned long c, const unsigned long d) {
|
||||
const unsigned long lowBits = ((a & 0x030303) + (b & 0x030303) + (c & 0x030303) + (d & 0x030303)) & 0x030303;
|
||||
|
||||
return (a + b + c + d - lowBits) >> 2;
|
||||
}
|
||||
|
||||
template<unsigned srcPitch, unsigned width, unsigned height>
|
||||
static void filter(gambatte::uint_least32_t *dstPtr, const int dstPitch, const gambatte::uint_least32_t *srcPtr)
|
||||
{
|
||||
unsigned h = height;
|
||||
|
||||
while (h--) {
|
||||
const gambatte::uint_least32_t *bP = srcPtr;
|
||||
gambatte::uint_least32_t *dP = dstPtr;
|
||||
|
||||
for (unsigned finish = width; finish--;) {
|
||||
register unsigned long colorA, colorB;
|
||||
unsigned long colorC, colorD,
|
||||
colorE, colorF, colorG, colorH,
|
||||
colorI, colorJ, colorK, colorL,
|
||||
|
||||
colorM, colorN, colorO, colorP;
|
||||
unsigned long product, product1, product2;
|
||||
|
||||
//---------------------------------------
|
||||
// Map of the pixels: I|E F|J
|
||||
// G|A B|K
|
||||
// H|C D|L
|
||||
// M|N O|P
|
||||
colorI = *(bP - srcPitch - 1);
|
||||
colorE = *(bP - srcPitch);
|
||||
colorF = *(bP - srcPitch + 1);
|
||||
colorJ = *(bP - srcPitch + 2);
|
||||
|
||||
colorG = *(bP - 1);
|
||||
colorA = *(bP);
|
||||
colorB = *(bP + 1);
|
||||
colorK = *(bP + 2);
|
||||
|
||||
colorH = *(bP + srcPitch - 1);
|
||||
colorC = *(bP + srcPitch);
|
||||
colorD = *(bP + srcPitch + 1);
|
||||
colorL = *(bP + srcPitch + 2);
|
||||
|
||||
colorM = *(bP + srcPitch * 2 - 1);
|
||||
colorN = *(bP + srcPitch * 2);
|
||||
colorO = *(bP + srcPitch * 2 + 1);
|
||||
colorP = *(bP + srcPitch * 2 + 2);
|
||||
|
||||
if (colorA == colorD && colorB != colorC) {
|
||||
if ((colorA == colorE && colorB == colorL) ||
|
||||
(colorA == colorC && colorA == colorF
|
||||
&& colorB != colorE && colorB == colorJ)) {
|
||||
product = colorA;
|
||||
} else {
|
||||
product = interpolate(colorA, colorB);
|
||||
}
|
||||
|
||||
if ((colorA == colorG && colorC == colorO) ||
|
||||
(colorA == colorB && colorA == colorH
|
||||
&& colorG != colorC && colorC == colorM)) {
|
||||
product1 = colorA;
|
||||
} else {
|
||||
product1 = interpolate(colorA, colorC);
|
||||
}
|
||||
product2 = colorA;
|
||||
} else if (colorB == colorC && colorA != colorD) {
|
||||
if ((colorB == colorF && colorA == colorH) ||
|
||||
(colorB == colorE && colorB == colorD
|
||||
&& colorA != colorF && colorA == colorI)) {
|
||||
product = colorB;
|
||||
} else {
|
||||
product = interpolate(colorA, colorB);
|
||||
}
|
||||
|
||||
if ((colorC == colorH && colorA == colorF) ||
|
||||
(colorC == colorG && colorC == colorD
|
||||
&& colorA != colorH && colorA == colorI)) {
|
||||
product1 = colorC;
|
||||
} else {
|
||||
product1 = interpolate(colorA, colorC);
|
||||
}
|
||||
product2 = colorB;
|
||||
} else if (colorA == colorD && colorB == colorC) {
|
||||
if (colorA == colorB) {
|
||||
product = colorA;
|
||||
product1 = colorA;
|
||||
product2 = colorA;
|
||||
} else {
|
||||
register int r = 0;
|
||||
|
||||
product1 = interpolate(colorA, colorC);
|
||||
product = interpolate(colorA, colorB);
|
||||
|
||||
r += getResult1(colorA, colorB, colorG, colorE);
|
||||
r += getResult2(colorB, colorA, colorK, colorF);
|
||||
r += getResult2(colorB, colorA, colorH, colorN);
|
||||
r += getResult1(colorA, colorB, colorL, colorO);
|
||||
|
||||
if (r > 0)
|
||||
product2 = colorA;
|
||||
else if (r < 0)
|
||||
product2 = colorB;
|
||||
else {
|
||||
product2 = qInterpolate(colorA, colorB, colorC, colorD);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
product2 = qInterpolate(colorA, colorB, colorC, colorD);
|
||||
|
||||
if (colorA == colorC && colorA == colorF
|
||||
&& colorB != colorE && colorB == colorJ) {
|
||||
product = colorA;
|
||||
} else if (colorB == colorE && colorB == colorD
|
||||
&& colorA != colorF && colorA == colorI) {
|
||||
product = colorB;
|
||||
} else {
|
||||
product = interpolate(colorA, colorB);
|
||||
}
|
||||
|
||||
if (colorA == colorB && colorA == colorH
|
||||
&& colorG != colorC && colorC == colorM) {
|
||||
product1 = colorA;
|
||||
} else if (colorC == colorG && colorC == colorD
|
||||
&& colorA != colorH && colorA == colorI) {
|
||||
product1 = colorC;
|
||||
} else {
|
||||
product1 = interpolate(colorA, colorC);
|
||||
}
|
||||
}
|
||||
*dP = colorA;
|
||||
*(dP + 1) = product;
|
||||
*(dP + dstPitch) = product1;
|
||||
*(dP + dstPitch + 1) = product2;
|
||||
|
||||
++bP;
|
||||
dP += 2;
|
||||
}
|
||||
|
||||
srcPtr += srcPitch;
|
||||
dstPtr += dstPitch * 2;
|
||||
}
|
||||
}
|
||||
|
||||
enum { WIDTH = VfilterInfo::IN_WIDTH };
|
||||
enum { HEIGHT = VfilterInfo::IN_HEIGHT };
|
||||
enum { PITCH = WIDTH + 3 };
|
||||
enum { BUF_SIZE = (HEIGHT + 3) * PITCH };
|
||||
enum { BUF_OFFSET = PITCH + 1 };
|
||||
|
||||
}
|
||||
|
||||
Kreed2xSaI::Kreed2xSaI()
|
||||
: buffer_(BUF_SIZE)
|
||||
{
|
||||
std::fill_n(buffer_.get(), buffer_.size(), 0);
|
||||
}
|
||||
|
||||
void* Kreed2xSaI::inBuf() const {
|
||||
return buffer_ + BUF_OFFSET;
|
||||
}
|
||||
|
||||
int Kreed2xSaI::inPitch() const {
|
||||
return PITCH;
|
||||
}
|
||||
|
||||
void Kreed2xSaI::draw(void *const dbuffer, const int pitch) {
|
||||
::filter<PITCH, WIDTH, HEIGHT>(static_cast<gambatte::uint_least32_t*>(dbuffer), pitch, buffer_ + BUF_OFFSET);
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef KREED2XSAI_H
|
||||
#define KREED2XSAI_H
|
||||
|
||||
#include "../videolink.h"
|
||||
#include "../vfilterinfo.h"
|
||||
#include "array.h"
|
||||
#include "gbint.h"
|
||||
|
||||
class Kreed2xSaI : public VideoLink {
|
||||
const Array<gambatte::uint_least32_t> buffer_;
|
||||
public:
|
||||
enum { OUT_WIDTH = VfilterInfo::IN_WIDTH * 2 };
|
||||
enum { OUT_HEIGHT = VfilterInfo::IN_HEIGHT * 2 };
|
||||
|
||||
Kreed2xSaI();
|
||||
virtual void* inBuf() const;
|
||||
virtual int inPitch() const;
|
||||
virtual void draw(void *dst, int dstpitch);
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,39 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef MAXSTHQ2X_H
|
||||
#define MAXSTHQ2X_H
|
||||
|
||||
#include "../videolink.h"
|
||||
#include "../vfilterinfo.h"
|
||||
#include "array.h"
|
||||
#include "gbint.h"
|
||||
|
||||
class MaxStHq2x : public VideoLink {
|
||||
const Array<gambatte::uint_least32_t> buffer_;
|
||||
public:
|
||||
enum { OUT_WIDTH = VfilterInfo::IN_WIDTH * 2 };
|
||||
enum { OUT_HEIGHT = VfilterInfo::IN_HEIGHT * 2 };
|
||||
|
||||
MaxStHq2x();
|
||||
virtual void* inBuf() const;
|
||||
virtual int inPitch() const;
|
||||
virtual void draw(void *dst, int dstpitch);
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,39 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef MAXSTHQ3X_H
|
||||
#define MAXSTHQ3X_H
|
||||
|
||||
#include "../videolink.h"
|
||||
#include "../vfilterinfo.h"
|
||||
#include "array.h"
|
||||
#include "gbint.h"
|
||||
|
||||
class MaxStHq3x : public VideoLink {
|
||||
const Array<gambatte::uint_least32_t> buffer_;
|
||||
public:
|
||||
enum { OUT_WIDTH = VfilterInfo::IN_WIDTH * 3 };
|
||||
enum { OUT_HEIGHT = VfilterInfo::IN_HEIGHT * 3 };
|
||||
|
||||
MaxStHq3x();
|
||||
virtual void* inBuf() const;
|
||||
virtual int inPitch() const;
|
||||
virtual void draw(void *dst, int dstpitch);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,30 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef VIDEOLINK_H
|
||||
#define VIDEOLINK_H
|
||||
|
||||
class VideoLink {
|
||||
public:
|
||||
virtual ~VideoLink() {}
|
||||
virtual void* inBuf() const = 0;
|
||||
virtual int inPitch() const = 0;
|
||||
virtual void draw(void *dst, int dstpitch) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,56 +0,0 @@
|
||||
global_cflags = ARGUMENTS.get('CFLAGS', '-Wall -Wextra -O2 -fomit-frame-pointer')
|
||||
global_cxxflags = ARGUMENTS.get('CXXFLAGS', global_cflags + ' -fno-exceptions -fno-rtti')
|
||||
global_defines = ' -DHAVE_STDINT_H'
|
||||
vars = Variables()
|
||||
vars.Add('CC')
|
||||
vars.Add('CXX')
|
||||
|
||||
env = Environment(CPPPATH = ['src', 'include', '../common'],
|
||||
CFLAGS = global_cflags + global_defines,
|
||||
CXXFLAGS = global_cxxflags + global_defines,
|
||||
variables = vars)
|
||||
|
||||
sourceFiles = Split('''
|
||||
src/bitmap_font.cpp
|
||||
src/cpu.cpp
|
||||
src/gambatte.cpp
|
||||
src/initstate.cpp
|
||||
src/interrupter.cpp
|
||||
src/interruptrequester.cpp
|
||||
src/loadres.cpp
|
||||
src/memory.cpp
|
||||
src/sound.cpp
|
||||
src/state_osd_elements.cpp
|
||||
src/statesaver.cpp
|
||||
src/tima.cpp
|
||||
src/video.cpp
|
||||
src/mem/cartridge.cpp
|
||||
src/mem/memptrs.cpp
|
||||
src/mem/pakinfo.cpp
|
||||
src/mem/rtc.cpp
|
||||
src/sound/channel1.cpp
|
||||
src/sound/channel2.cpp
|
||||
src/sound/channel3.cpp
|
||||
src/sound/channel4.cpp
|
||||
src/sound/duty_unit.cpp
|
||||
src/sound/envelope_unit.cpp
|
||||
src/sound/length_counter.cpp
|
||||
src/video/ly_counter.cpp
|
||||
src/video/lyc_irq.cpp
|
||||
src/video/next_m0_time.cpp
|
||||
src/video/ppu.cpp
|
||||
src/video/sprite_mapper.cpp
|
||||
''')
|
||||
|
||||
conf = env.Configure()
|
||||
|
||||
if conf.CheckHeader('zlib.h'):
|
||||
sourceFiles.append('src/file/unzip/unzip.c')
|
||||
sourceFiles.append('src/file/unzip/ioapi.c')
|
||||
sourceFiles.append('src/file/file_zip.cpp')
|
||||
else:
|
||||
sourceFiles.append('src/file/file.cpp')
|
||||
|
||||
conf.Finish()
|
||||
|
||||
env.Library('gambatte', sourceFiles)
|
||||
@@ -1,166 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef GAMBATTE_H
|
||||
#define GAMBATTE_H
|
||||
|
||||
#include "inputgetter.h"
|
||||
#include "loadres.h"
|
||||
#include "gbint.h"
|
||||
#include <string>
|
||||
|
||||
namespace gambatte {
|
||||
enum { BG_PALETTE = 0, SP1_PALETTE = 1, SP2_PALETTE = 2 };
|
||||
|
||||
class GB {
|
||||
public:
|
||||
GB();
|
||||
~GB();
|
||||
|
||||
enum LoadFlag {
|
||||
FORCE_DMG = 1, /**< Treat the ROM as not having CGB support regardless of what its header advertises. */
|
||||
GBA_CGB = 2, /**< Use GBA intial CPU register values when in CGB mode. */
|
||||
MULTICART_COMPAT = 4 /**< Use heuristics to detect and support some multicart MBCs disguised as MBC1. */
|
||||
};
|
||||
|
||||
/** Load ROM image.
|
||||
*
|
||||
* @param romfile Path to rom image file. Typically a .gbc, .gb, or .zip-file (if zip-support is compiled in).
|
||||
* @param flags ORed combination of LoadFlags.
|
||||
* @return 0 on success, negative value on failure.
|
||||
*/
|
||||
LoadRes load(const std::string &romfile, unsigned flags = 0);
|
||||
|
||||
/** Emulates until at least 'samples' stereo sound samples are produced in the supplied buffer,
|
||||
* or until a video frame has been drawn.
|
||||
*
|
||||
* There are 35112 stereo sound samples in a video frame.
|
||||
* May run for up to 2064 stereo samples too long.
|
||||
* A stereo sample consists of two native endian 2s complement 16-bit PCM samples,
|
||||
* with the left sample preceding the right one. Usually casting soundBuf to/from
|
||||
* short* is OK and recommended. The reason for not using a short* in the interface
|
||||
* is to avoid implementation-defined behaviour without compromising performance.
|
||||
*
|
||||
* Returns early when a new video frame has finished drawing in the video buffer,
|
||||
* such that the caller may update the video output before the frame is overwritten.
|
||||
* The return value indicates whether a new video frame has been drawn, and the
|
||||
* exact time (in number of samples) at which it was drawn.
|
||||
*
|
||||
* @param videoBuf 160x144 RGB32 (native endian) video frame buffer or 0
|
||||
* @param pitch distance in number of pixels (not bytes) from the start of one line to the next in videoBuf.
|
||||
* @param soundBuf buffer with space >= samples + 2064
|
||||
* @param samples in: number of stereo samples to produce, out: actual number of samples produced
|
||||
* @return sample number at which the video frame was produced. -1 means no frame was produced.
|
||||
*/
|
||||
long runFor(gambatte::uint_least32_t *videoBuf, int pitch,
|
||||
gambatte::uint_least32_t *soundBuf, unsigned &samples);
|
||||
|
||||
/** Reset to initial state.
|
||||
* Equivalent to reloading a ROM image, or turning a Game Boy Color off and on again.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/** @param palNum 0 <= palNum < 3. One of BG_PALETTE, SP1_PALETTE and SP2_PALETTE.
|
||||
* @param colorNum 0 <= colorNum < 4
|
||||
*/
|
||||
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32);
|
||||
|
||||
/** Sets the callback used for getting input state. */
|
||||
void setInputGetter(InputGetter *getInput);
|
||||
|
||||
/** Sets the directory used for storing save data. The default is the same directory as the ROM Image file. */
|
||||
void setSaveDir(const std::string &sdir);
|
||||
|
||||
/** Returns true if the currently loaded ROM image is treated as having CGB support. */
|
||||
bool isCgb() const;
|
||||
|
||||
/** Returns true if a ROM image is loaded. */
|
||||
bool isLoaded() const;
|
||||
|
||||
/** Writes persistent cartridge data to disk. Done implicitly on ROM close. */
|
||||
//void saveSavedata();
|
||||
|
||||
void *savedata_ptr();
|
||||
unsigned savedata_size();
|
||||
void *rtcdata_ptr();
|
||||
unsigned rtcdata_size();
|
||||
|
||||
/** Saves emulator state to the state slot selected with selectState().
|
||||
* The data will be stored in the directory given by setSaveDir().
|
||||
*
|
||||
* @param videoBuf 160x144 RGB32 (native endian) video frame buffer or 0. Used for saving a thumbnail.
|
||||
* @param pitch distance in number of pixels (not bytes) from the start of one line to the next in videoBuf.
|
||||
* @return success
|
||||
*/
|
||||
//bool saveState(const gambatte::uint_least32_t *videoBuf, int pitch);
|
||||
|
||||
/** Loads emulator state from the state slot selected with selectState().
|
||||
* @return success
|
||||
*/
|
||||
//bool loadState();
|
||||
|
||||
/** Saves emulator state to the file given by 'filepath'.
|
||||
*
|
||||
* @param videoBuf 160x144 RGB32 (native endian) video frame buffer or 0. Used for saving a thumbnail.
|
||||
* @param pitch distance in number of pixels (not bytes) from the start of one line to the next in videoBuf.
|
||||
* @return success
|
||||
*/
|
||||
//bool saveState(const gambatte::uint_least32_t *videoBuf, int pitch, const std::string &filepath);
|
||||
|
||||
/** Loads emulator state from the file given by 'filepath'.
|
||||
* @return success
|
||||
*/
|
||||
//bool loadState(const std::string &filepath);
|
||||
void saveState(void *data);
|
||||
void loadState(const void *data);
|
||||
size_t stateSize() const;
|
||||
|
||||
/** Selects which state slot to save state to or load state from.
|
||||
* There are 10 such slots, numbered from 0 to 9 (periodically extended for all n).
|
||||
*/
|
||||
//void selectState(int n);
|
||||
|
||||
/** Current state slot selected with selectState(). Returns a value between 0 and 9 inclusive. */
|
||||
//int currentState() const;
|
||||
|
||||
/** ROM header title of currently loaded ROM image. */
|
||||
std::string const romTitle() const;
|
||||
|
||||
/** GamePak/Cartridge info. */
|
||||
class PakInfo const pakInfo() const;
|
||||
|
||||
/** Set Game Genie codes to apply to currently loaded ROM image. Cleared on ROM load.
|
||||
* @param codes Game Genie codes in format HHH-HHH-HHH;HHH-HHH-HHH;... where H is [0-9]|[A-F]
|
||||
*/
|
||||
void setGameGenie(const std::string &codes);
|
||||
|
||||
/** Set Game Shark codes to apply to currently loaded ROM image. Cleared on ROM load.
|
||||
* @param codes Game Shark codes in format 01HHHHHH;01HHHHHH;... where H is [0-9]|[A-F]
|
||||
*/
|
||||
void setGameShark(const std::string &codes);
|
||||
|
||||
private:
|
||||
struct Priv;
|
||||
Priv *const p_;
|
||||
|
||||
GB(const GB &);
|
||||
GB & operator=(const GB &);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,62 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef GAMBATTE_INT_H
|
||||
#define GAMBATTE_INT_H
|
||||
|
||||
#ifdef HAVE_CSTDINT
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace gambatte {
|
||||
using std::uint_least32_t;
|
||||
using std::uint_least16_t;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_STDINT_H)
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace gambatte {
|
||||
using ::uint_least32_t;
|
||||
using ::uint_least16_t;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace gambatte {
|
||||
#ifdef CHAR_LEAST_32
|
||||
typedef unsigned char uint_least32_t;
|
||||
#elif defined(SHORT_LEAST_32)
|
||||
typedef unsigned short uint_least32_t;
|
||||
#elif defined(INT_LEAST_32)
|
||||
typedef unsigned uint_least32_t;
|
||||
#else
|
||||
typedef unsigned long uint_least32_t;
|
||||
#endif
|
||||
|
||||
#ifdef CHAR_LEAST_16
|
||||
typedef unsigned char uint_least16_t;
|
||||
#else
|
||||
typedef unsigned short uint_least16_t;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef GAMBATTE_INPUTGETTER_H
|
||||
#define GAMBATTE_INPUTGETTER_H
|
||||
|
||||
namespace gambatte {
|
||||
class InputGetter {
|
||||
public:
|
||||
enum { A = 0x01, B = 0x02, SELECT = 0x04, START = 0x08, RIGHT = 0x10, LEFT = 0x20, UP = 0x40, DOWN = 0x80 };
|
||||
virtual ~InputGetter() {};
|
||||
|
||||
/** @return A|B|SELECT|START|RIGHT|LEFT|UP|DOWN if those buttons are pressed. */
|
||||
virtual unsigned operator()() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,429 +0,0 @@
|
||||
#include "libretro.h"
|
||||
#include "resamplerinfo.h"
|
||||
#include "gbcpalettes.h"
|
||||
|
||||
#include <gambatte.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
static retro_video_refresh_t video_cb;
|
||||
static retro_input_poll_t input_poll_cb;
|
||||
static retro_input_state_t input_state_cb;
|
||||
static retro_audio_sample_batch_t audio_batch_cb;
|
||||
static retro_environment_t environ_cb;
|
||||
static gambatte::GB gb;
|
||||
static bool g_has_rgb32;
|
||||
|
||||
namespace input
|
||||
{
|
||||
struct map { unsigned snes; unsigned gb; };
|
||||
static const map btn_map[] = {
|
||||
{ RETRO_DEVICE_ID_JOYPAD_A, gambatte::InputGetter::A },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_B, gambatte::InputGetter::B },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_SELECT, gambatte::InputGetter::SELECT },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_START, gambatte::InputGetter::START },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_RIGHT, gambatte::InputGetter::RIGHT },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_LEFT, gambatte::InputGetter::LEFT },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_UP, gambatte::InputGetter::UP },
|
||||
{ RETRO_DEVICE_ID_JOYPAD_DOWN, gambatte::InputGetter::DOWN },
|
||||
};
|
||||
}
|
||||
|
||||
class SNESInput : public gambatte::InputGetter
|
||||
{
|
||||
public:
|
||||
unsigned operator()()
|
||||
{
|
||||
input_poll_cb();
|
||||
unsigned res = 0;
|
||||
for (unsigned i = 0; i < sizeof(input::btn_map) / sizeof(input::map); i++)
|
||||
res |= input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, input::btn_map[i].snes) ? input::btn_map[i].gb : 0;
|
||||
return res;
|
||||
}
|
||||
} static gb_input;
|
||||
|
||||
static Resampler *resampler;
|
||||
|
||||
|
||||
void retro_get_system_info(struct retro_system_info *info)
|
||||
{
|
||||
info->library_name = "gambatte";
|
||||
info->library_version = "v0.5.0";
|
||||
info->need_fullpath = false;
|
||||
info->block_extract = false;
|
||||
info->valid_extensions = "gb|gbc|dmg|zip|GB|GBC|DMG|ZIP";
|
||||
}
|
||||
|
||||
static bool can_dupe = false;
|
||||
static struct retro_system_timing g_timing;
|
||||
|
||||
void retro_get_system_av_info(struct retro_system_av_info *info)
|
||||
{
|
||||
retro_game_geometry geom = { 160, 144, 160, 144 };
|
||||
info->geometry = geom;
|
||||
info->timing = g_timing;
|
||||
}
|
||||
|
||||
void retro_init()
|
||||
{
|
||||
// Using uint_least32_t in an audio interface expecting you to cast to short*? :( Weird stuff.
|
||||
assert(sizeof(gambatte::uint_least32_t) == sizeof(uint32_t));
|
||||
gb.setInputGetter(&gb_input);
|
||||
|
||||
double fps = 4194304.0 / 70224.0;
|
||||
double sample_rate = fps * 35112;
|
||||
|
||||
resampler = ResamplerInfo::get(ResamplerInfo::num() - 2).create(sample_rate, 48000.0, 2 * 2064);
|
||||
|
||||
if (environ_cb)
|
||||
{
|
||||
g_timing.fps = fps;
|
||||
|
||||
unsigned long mul, div;
|
||||
resampler->exactRatio(mul, div);
|
||||
|
||||
g_timing.sample_rate = sample_rate * mul / div;
|
||||
|
||||
environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &can_dupe);
|
||||
if (can_dupe)
|
||||
fprintf(stderr, "[Gambatte]: Will dupe frames with NULL!\n");
|
||||
}
|
||||
}
|
||||
|
||||
void retro_deinit()
|
||||
{
|
||||
delete resampler;
|
||||
}
|
||||
|
||||
void retro_set_environment(retro_environment_t cb) { environ_cb = cb; }
|
||||
void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; }
|
||||
void retro_set_audio_sample(retro_audio_sample_t) {}
|
||||
void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) { audio_batch_cb = cb; }
|
||||
void retro_set_input_poll(retro_input_poll_t cb) { input_poll_cb = cb; }
|
||||
void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; }
|
||||
|
||||
void retro_set_controller_port_device(unsigned, unsigned) {}
|
||||
|
||||
void retro_reset()
|
||||
{
|
||||
// gambatte seems to clear out SRAM and RTC on reset.
|
||||
uint8_t *sram = 0;
|
||||
unsigned *rtc = 0;
|
||||
if (gb.savedata_size())
|
||||
{
|
||||
sram = new uint8_t[gb.savedata_size()];
|
||||
memcpy(sram, gb.savedata_ptr(), gb.savedata_size());
|
||||
}
|
||||
|
||||
if (gb.rtcdata_size())
|
||||
{
|
||||
rtc = new unsigned[4];
|
||||
memcpy(rtc, gb.rtcdata_ptr(), 4);
|
||||
}
|
||||
|
||||
gb.reset();
|
||||
|
||||
if (sram)
|
||||
{
|
||||
memcpy(gb.savedata_ptr(), sram, gb.savedata_size());
|
||||
delete[] sram;
|
||||
}
|
||||
|
||||
if (rtc)
|
||||
{
|
||||
memcpy(gb.rtcdata_ptr(), rtc, 4);
|
||||
delete[] rtc;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t serialize_size = 0;
|
||||
size_t retro_serialize_size()
|
||||
{
|
||||
return gb.stateSize();
|
||||
}
|
||||
|
||||
bool retro_serialize(void *data, size_t size)
|
||||
{
|
||||
if (serialize_size == 0)
|
||||
serialize_size = retro_serialize_size();
|
||||
|
||||
if (size != serialize_size)
|
||||
return false;
|
||||
|
||||
gb.saveState(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool retro_unserialize(const void *data, size_t size)
|
||||
{
|
||||
if (serialize_size == 0)
|
||||
serialize_size = retro_serialize_size();
|
||||
|
||||
if (size != serialize_size)
|
||||
return false;
|
||||
|
||||
gb.loadState(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
void retro_cheat_reset() {}
|
||||
void retro_cheat_set(unsigned index, bool enabled, const char *code, const char *type)
|
||||
{
|
||||
if (!strcmp(type, "GameShark"))
|
||||
gb.setGameShark(code);
|
||||
|
||||
if (!strcmp(type, "Game Genie"))
|
||||
gb.setGameGenie(code);
|
||||
}
|
||||
|
||||
static std::string basename(std::string filename)
|
||||
{
|
||||
// Remove directory if present.
|
||||
// Do this before extension removal incase directory has a period character.
|
||||
const size_t last_slash_idx = filename.find_last_of("\\/");
|
||||
if (std::string::npos != last_slash_idx)
|
||||
filename.erase(0, last_slash_idx + 1);
|
||||
|
||||
// Remove extension if present.
|
||||
const size_t period_idx = filename.rfind('.');
|
||||
if (std::string::npos != period_idx)
|
||||
filename.erase(period_idx);
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
static bool startswith(const std::string s1, const std::string prefix)
|
||||
{
|
||||
return s1.compare(0, prefix.length(), prefix) == 0;
|
||||
}
|
||||
|
||||
bool retro_load_game(const struct retro_game_info *info)
|
||||
{
|
||||
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
|
||||
if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
|
||||
g_has_rgb32 = true;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "[gambatte]: XRGB8888 is not supported. Will have to perform slow conversion to ARGB1555.\n");
|
||||
g_has_rgb32 = false;
|
||||
}
|
||||
|
||||
//const std::string romFile = reinterpret_cast<const char *>(info->path);
|
||||
|
||||
if (gb.load(reinterpret_cast<const char *>(info->path)))
|
||||
return false;
|
||||
|
||||
if (gb.isCgb())
|
||||
return true;
|
||||
// else it is a GB-mono game -> set a color palette
|
||||
|
||||
std::string str = gb.romTitle(); // read ROM internal title
|
||||
const char * internal_game_name = str.c_str();
|
||||
|
||||
// load a GBC BIOS builtin palette
|
||||
unsigned short* gbc_bios_palette = NULL;
|
||||
gbc_bios_palette = const_cast<unsigned short*>(findGbcTitlePal(internal_game_name));
|
||||
|
||||
if (gbc_bios_palette == 0)
|
||||
{
|
||||
// no custom palette found, load the default (Original Grayscale)
|
||||
gbc_bios_palette = const_cast<unsigned short*>(findGbcDirPal("GBC - Grayscale"));
|
||||
}
|
||||
|
||||
unsigned rgb32 = 0;
|
||||
for (unsigned palnum = 0; palnum < 3; ++palnum)
|
||||
{
|
||||
for (unsigned colornum = 0; colornum < 4; ++colornum)
|
||||
{
|
||||
rgb32 = gbcToRgb32(gbc_bios_palette[palnum * 4 + colornum]);
|
||||
gb.setDmgPaletteColor(palnum, colornum, rgb32);
|
||||
}
|
||||
}
|
||||
|
||||
const char *system_directory_c = NULL;
|
||||
environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system_directory_c);
|
||||
if (!system_directory_c)
|
||||
{
|
||||
fprintf(stderr, "[Gambatte]: no system directory defined, unable to look for custom palettes.\n");
|
||||
return true;
|
||||
}
|
||||
std::string system_directory(system_directory_c);
|
||||
|
||||
std::string custom_palette_path = system_directory + "/palettes/" + basename(info->path) + ".pal";
|
||||
|
||||
std::ifstream palette_file(custom_palette_path.c_str()); // try to open the palette file in read-only mode
|
||||
|
||||
if (!palette_file.is_open())
|
||||
{
|
||||
// try again with the internal game name from the ROM header
|
||||
custom_palette_path = system_directory + "/palettes/" + std::string(internal_game_name) + ".pal";
|
||||
palette_file.open(custom_palette_path.c_str());
|
||||
}
|
||||
|
||||
if (!palette_file.is_open())
|
||||
{
|
||||
// try again with default.pal
|
||||
// this will override any specific title palette found from the GBC BIOS
|
||||
custom_palette_path = system_directory + "/palettes/" + "default.pal";
|
||||
palette_file.open(custom_palette_path.c_str());
|
||||
}
|
||||
|
||||
if (!palette_file.is_open())
|
||||
{
|
||||
// unable to find any custom palette file
|
||||
return true;
|
||||
}
|
||||
|
||||
// fprintf(stderr, "[Gambatte]: using custom palette %s.\n", custom_palette_path.c_str());
|
||||
unsigned line_count = 0;
|
||||
for (std::string line; getline(palette_file, line); ) // iterate over file lines
|
||||
{
|
||||
line_count++;
|
||||
|
||||
if (line[0]=='[') // skip ini sections
|
||||
continue;
|
||||
|
||||
if (line[0]==';') // skip ini comments
|
||||
continue;
|
||||
|
||||
if (line[0]=='\n') // skip empty lines
|
||||
continue;
|
||||
|
||||
if (line.find("=") == std::string::npos)
|
||||
{
|
||||
fprintf(stderr, "[Gambatte]: error in %s, line %d (color left as default).\n", custom_palette_path.c_str(), line_count);
|
||||
continue; // current line does not contain a palette color definition, so go to next line
|
||||
}
|
||||
|
||||
// Supposed to be a typo here.
|
||||
if (startswith(line, "slectedScheme="))
|
||||
continue;
|
||||
|
||||
std::string line_value = line.substr(line.find("=") + 1); // extract the color value string
|
||||
std::stringstream ss(line_value); // convert the color value to int
|
||||
ss >> rgb32;
|
||||
if (!ss)
|
||||
{
|
||||
fprintf(stderr, "[Gambatte]: unable to read palette color in %s, line %d (color left as default).\n", custom_palette_path.c_str(), line_count);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (startswith(line, "Background0="))
|
||||
gb.setDmgPaletteColor(0, 0, rgb32);
|
||||
else if (startswith(line, "Background1="))
|
||||
gb.setDmgPaletteColor(0, 1, rgb32);
|
||||
else if (startswith(line, "Background2="))
|
||||
gb.setDmgPaletteColor(0, 2, rgb32);
|
||||
else if (startswith(line, "Background3="))
|
||||
gb.setDmgPaletteColor(0, 3, rgb32);
|
||||
else if (startswith(line, "Sprite%2010="))
|
||||
gb.setDmgPaletteColor(1, 0, rgb32);
|
||||
else if (startswith(line, "Sprite%2011="))
|
||||
gb.setDmgPaletteColor(1, 1, rgb32);
|
||||
else if (startswith(line, "Sprite%2012="))
|
||||
gb.setDmgPaletteColor(1, 2, rgb32);
|
||||
else if (startswith(line, "Sprite%2013="))
|
||||
gb.setDmgPaletteColor(1, 3, rgb32);
|
||||
else if (startswith(line, "Sprite%2020="))
|
||||
gb.setDmgPaletteColor(2, 0, rgb32);
|
||||
else if (startswith(line, "Sprite%2021="))
|
||||
gb.setDmgPaletteColor(2, 1, rgb32);
|
||||
else if (startswith(line, "Sprite%2022="))
|
||||
gb.setDmgPaletteColor(2, 2, rgb32);
|
||||
else if (startswith(line, "Sprite%2023="))
|
||||
gb.setDmgPaletteColor(2, 3, rgb32);
|
||||
else
|
||||
fprintf(stderr, "[Gambatte]: error in %s, line %d (color left as default).\n", custom_palette_path.c_str(), line_count);
|
||||
|
||||
} // endfor
|
||||
|
||||
palette_file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool retro_load_game_special(unsigned, const struct retro_game_info*, size_t) { return false; }
|
||||
|
||||
void retro_unload_game() {}
|
||||
|
||||
unsigned retro_get_region() { return RETRO_REGION_NTSC; }
|
||||
|
||||
void *retro_get_memory_data(unsigned id)
|
||||
{
|
||||
if (id == RETRO_MEMORY_SAVE_RAM)
|
||||
return gb.savedata_ptr();
|
||||
if (id == RETRO_MEMORY_RTC)
|
||||
return gb.rtcdata_ptr();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t retro_get_memory_size(unsigned id)
|
||||
{
|
||||
if (id == RETRO_MEMORY_SAVE_RAM)
|
||||
return gb.savedata_size();
|
||||
if (id == RETRO_MEMORY_RTC)
|
||||
//return gb.rtcdata_size();
|
||||
return 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void output_audio(const int16_t *samples, unsigned frames)
|
||||
{
|
||||
if (!frames)
|
||||
return;
|
||||
|
||||
int16_t output[2 * 2064];
|
||||
std::size_t len = resampler->resample(output, samples, frames);
|
||||
|
||||
if (len)
|
||||
audio_batch_cb(output, len);
|
||||
}
|
||||
|
||||
void retro_run()
|
||||
{
|
||||
static uint64_t samples_count = 0;
|
||||
static uint64_t frames_count = 0;
|
||||
static uint16_t output_video[256 * 144];
|
||||
|
||||
input_poll_cb();
|
||||
|
||||
uint64_t expected_frames = samples_count / 35112;
|
||||
if (frames_count < expected_frames) // Detect frame dupes.
|
||||
{
|
||||
video_cb(can_dupe ? 0 : output_video, 160, 144, 512);
|
||||
frames_count++;
|
||||
return;
|
||||
}
|
||||
|
||||
union
|
||||
{
|
||||
gambatte::uint_least32_t u32[2064 + 2064];
|
||||
int16_t i16[2 * (2064 + 2064)];
|
||||
} sound_buf;
|
||||
unsigned samples = 2064;
|
||||
|
||||
gambatte::uint_least32_t video_buf[256 * 144];
|
||||
gambatte::uint_least32_t param2 = 256;
|
||||
while (gb.runFor(video_buf, param2, sound_buf.u32, samples) == -1)
|
||||
{
|
||||
output_audio(sound_buf.i16, samples);
|
||||
samples_count += samples;
|
||||
samples = 2064;
|
||||
}
|
||||
|
||||
samples_count += samples;
|
||||
output_audio(sound_buf.i16, samples);
|
||||
|
||||
|
||||
video_cb(video_buf, 160, 144, 1024);
|
||||
|
||||
|
||||
frames_count++;
|
||||
}
|
||||
|
||||
unsigned retro_api_version() { return RETRO_API_VERSION; }
|
||||
|
||||
@@ -1,573 +0,0 @@
|
||||
#ifndef LIBRETRO_H__
|
||||
#define LIBRETRO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant.
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#else
|
||||
#if defined(_MSC_VER) && !defined(SN_TARGET_PS3) && !defined(__cplusplus)
|
||||
#define bool unsigned char
|
||||
#define true 1
|
||||
#define false 0
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Used for checking API/ABI mismatches that can break libretro implementations.
|
||||
// It is not incremented for compatible changes.
|
||||
#define RETRO_API_VERSION 1
|
||||
|
||||
// Libretro's fundamental device abstractions.
|
||||
#define RETRO_DEVICE_MASK 0xff
|
||||
#define RETRO_DEVICE_NONE 0
|
||||
|
||||
// The JOYPAD is called RetroPad. It is essentially a Super Nintendo controller,
|
||||
// but with additional L2/R2/L3/R3 buttons, similar to a PS1 DualShock.
|
||||
#define RETRO_DEVICE_JOYPAD 1
|
||||
|
||||
// The mouse is a simple mouse, similar to Super Nintendo's mouse.
|
||||
// X and Y coordinates are reported relatively to last poll (poll callback).
|
||||
// It is up to the libretro implementation to keep track of where the mouse pointer is supposed to be on the screen.
|
||||
// The frontend must make sure not to interfere with its own hardware mouse pointer.
|
||||
#define RETRO_DEVICE_MOUSE 2
|
||||
|
||||
// KEYBOARD device lets one poll for raw key pressed.
|
||||
// It is poll based, so input callback will return with the current pressed state.
|
||||
#define RETRO_DEVICE_KEYBOARD 3
|
||||
|
||||
// Lightgun X/Y coordinates are reported relatively to last poll, similar to mouse.
|
||||
#define RETRO_DEVICE_LIGHTGUN 4
|
||||
|
||||
// The ANALOG device is an extension to JOYPAD (RetroPad).
|
||||
// Similar to DualShock it adds two analog sticks.
|
||||
// This is treated as a separate device type as it returns values in the full analog range
|
||||
// of [-0x8000, 0x7fff]. Positive X axis is right. Positive Y axis is down.
|
||||
// Only use ANALOG type when polling for analog values of the axes.
|
||||
#define RETRO_DEVICE_ANALOG 5
|
||||
|
||||
// These device types are specializations of the base types above.
|
||||
// They should only be used in retro_set_controller_type() to inform libretro implementations
|
||||
// about use of a very specific device type.
|
||||
//
|
||||
// In input state callback, however, only the base type should be used in the 'device' field.
|
||||
#define RETRO_DEVICE_JOYPAD_MULTITAP ((1 << 8) | RETRO_DEVICE_JOYPAD)
|
||||
#define RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE ((1 << 8) | RETRO_DEVICE_LIGHTGUN)
|
||||
#define RETRO_DEVICE_LIGHTGUN_JUSTIFIER ((2 << 8) | RETRO_DEVICE_LIGHTGUN)
|
||||
#define RETRO_DEVICE_LIGHTGUN_JUSTIFIERS ((3 << 8) | RETRO_DEVICE_LIGHTGUN)
|
||||
|
||||
// Buttons for the RetroPad (JOYPAD).
|
||||
// The placement of these is equivalent to placements on the Super Nintendo controller.
|
||||
// L2/R2/L3/R3 buttons correspond to the PS1 DualShock.
|
||||
#define RETRO_DEVICE_ID_JOYPAD_B 0
|
||||
#define RETRO_DEVICE_ID_JOYPAD_Y 1
|
||||
#define RETRO_DEVICE_ID_JOYPAD_SELECT 2
|
||||
#define RETRO_DEVICE_ID_JOYPAD_START 3
|
||||
#define RETRO_DEVICE_ID_JOYPAD_UP 4
|
||||
#define RETRO_DEVICE_ID_JOYPAD_DOWN 5
|
||||
#define RETRO_DEVICE_ID_JOYPAD_LEFT 6
|
||||
#define RETRO_DEVICE_ID_JOYPAD_RIGHT 7
|
||||
#define RETRO_DEVICE_ID_JOYPAD_A 8
|
||||
#define RETRO_DEVICE_ID_JOYPAD_X 9
|
||||
#define RETRO_DEVICE_ID_JOYPAD_L 10
|
||||
#define RETRO_DEVICE_ID_JOYPAD_R 11
|
||||
#define RETRO_DEVICE_ID_JOYPAD_L2 12
|
||||
#define RETRO_DEVICE_ID_JOYPAD_R2 13
|
||||
#define RETRO_DEVICE_ID_JOYPAD_L3 14
|
||||
#define RETRO_DEVICE_ID_JOYPAD_R3 15
|
||||
|
||||
// Index / Id values for ANALOG device.
|
||||
#define RETRO_DEVICE_INDEX_ANALOG_LEFT 0
|
||||
#define RETRO_DEVICE_INDEX_ANALOG_RIGHT 1
|
||||
#define RETRO_DEVICE_ID_ANALOG_X 0
|
||||
#define RETRO_DEVICE_ID_ANALOG_Y 1
|
||||
|
||||
// Id values for MOUSE.
|
||||
#define RETRO_DEVICE_ID_MOUSE_X 0
|
||||
#define RETRO_DEVICE_ID_MOUSE_Y 1
|
||||
#define RETRO_DEVICE_ID_MOUSE_LEFT 2
|
||||
#define RETRO_DEVICE_ID_MOUSE_RIGHT 3
|
||||
|
||||
// Id values for LIGHTGUN types.
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_X 0
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_Y 1
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER 2
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR 3
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_TURBO 4
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5
|
||||
#define RETRO_DEVICE_ID_LIGHTGUN_START 6
|
||||
|
||||
// Returned from retro_get_region().
|
||||
#define RETRO_REGION_NTSC 0
|
||||
#define RETRO_REGION_PAL 1
|
||||
|
||||
// Passed to retro_get_memory_data/size().
|
||||
// If the memory type doesn't apply to the implementation NULL/0 can be returned.
|
||||
#define RETRO_MEMORY_MASK 0xff
|
||||
|
||||
// Regular save ram. This ram is usually found on a game cartridge, backed up by a battery.
|
||||
// If save game data is too complex for a single memory buffer,
|
||||
// the SYSTEM_DIRECTORY environment callback can be used.
|
||||
#define RETRO_MEMORY_SAVE_RAM 0
|
||||
|
||||
// Some games have a built-in clock to keep track of time.
|
||||
// This memory is usually just a couple of bytes to keep track of time.
|
||||
#define RETRO_MEMORY_RTC 1
|
||||
|
||||
// System ram lets a frontend peek into a game systems main RAM.
|
||||
#define RETRO_MEMORY_SYSTEM_RAM 2
|
||||
|
||||
// Video ram lets a frontend peek into a game systems video RAM (VRAM).
|
||||
#define RETRO_MEMORY_VIDEO_RAM 3
|
||||
|
||||
// Special memory types.
|
||||
#define RETRO_MEMORY_SNES_BSX_RAM ((1 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_BSX_PRAM ((2 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM ((3 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM ((4 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_GAME_BOY_RAM ((5 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_GAME_BOY_RTC ((6 << 8) | RETRO_MEMORY_RTC)
|
||||
|
||||
// Special game types passed into retro_load_game_special().
|
||||
// Only used when multiple ROMs are required.
|
||||
#define RETRO_GAME_TYPE_BSX 0x101
|
||||
#define RETRO_GAME_TYPE_BSX_SLOTTED 0x102
|
||||
#define RETRO_GAME_TYPE_SUFAMI_TURBO 0x103
|
||||
#define RETRO_GAME_TYPE_SUPER_GAME_BOY 0x104
|
||||
|
||||
// Keysyms used for ID in input state callback when polling RETRO_KEYBOARD.
|
||||
enum retro_key
|
||||
{
|
||||
RETROK_UNKNOWN = 0,
|
||||
RETROK_FIRST = 0,
|
||||
RETROK_BACKSPACE = 8,
|
||||
RETROK_TAB = 9,
|
||||
RETROK_CLEAR = 12,
|
||||
RETROK_RETURN = 13,
|
||||
RETROK_PAUSE = 19,
|
||||
RETROK_ESCAPE = 27,
|
||||
RETROK_SPACE = 32,
|
||||
RETROK_EXCLAIM = 33,
|
||||
RETROK_QUOTEDBL = 34,
|
||||
RETROK_HASH = 35,
|
||||
RETROK_DOLLAR = 36,
|
||||
RETROK_AMPERSAND = 38,
|
||||
RETROK_QUOTE = 39,
|
||||
RETROK_LEFTPAREN = 40,
|
||||
RETROK_RIGHTPAREN = 41,
|
||||
RETROK_ASTERISK = 42,
|
||||
RETROK_PLUS = 43,
|
||||
RETROK_COMMA = 44,
|
||||
RETROK_MINUS = 45,
|
||||
RETROK_PERIOD = 46,
|
||||
RETROK_SLASH = 47,
|
||||
RETROK_0 = 48,
|
||||
RETROK_1 = 49,
|
||||
RETROK_2 = 50,
|
||||
RETROK_3 = 51,
|
||||
RETROK_4 = 52,
|
||||
RETROK_5 = 53,
|
||||
RETROK_6 = 54,
|
||||
RETROK_7 = 55,
|
||||
RETROK_8 = 56,
|
||||
RETROK_9 = 57,
|
||||
RETROK_COLON = 58,
|
||||
RETROK_SEMICOLON = 59,
|
||||
RETROK_LESS = 60,
|
||||
RETROK_EQUALS = 61,
|
||||
RETROK_GREATER = 62,
|
||||
RETROK_QUESTION = 63,
|
||||
RETROK_AT = 64,
|
||||
RETROK_LEFTBRACKET = 91,
|
||||
RETROK_BACKSLASH = 92,
|
||||
RETROK_RIGHTBRACKET = 93,
|
||||
RETROK_CARET = 94,
|
||||
RETROK_UNDERSCORE = 95,
|
||||
RETROK_BACKQUOTE = 96,
|
||||
RETROK_a = 97,
|
||||
RETROK_b = 98,
|
||||
RETROK_c = 99,
|
||||
RETROK_d = 100,
|
||||
RETROK_e = 101,
|
||||
RETROK_f = 102,
|
||||
RETROK_g = 103,
|
||||
RETROK_h = 104,
|
||||
RETROK_i = 105,
|
||||
RETROK_j = 106,
|
||||
RETROK_k = 107,
|
||||
RETROK_l = 108,
|
||||
RETROK_m = 109,
|
||||
RETROK_n = 110,
|
||||
RETROK_o = 111,
|
||||
RETROK_p = 112,
|
||||
RETROK_q = 113,
|
||||
RETROK_r = 114,
|
||||
RETROK_s = 115,
|
||||
RETROK_t = 116,
|
||||
RETROK_u = 117,
|
||||
RETROK_v = 118,
|
||||
RETROK_w = 119,
|
||||
RETROK_x = 120,
|
||||
RETROK_y = 121,
|
||||
RETROK_z = 122,
|
||||
RETROK_DELETE = 127,
|
||||
|
||||
RETROK_KP0 = 256,
|
||||
RETROK_KP1 = 257,
|
||||
RETROK_KP2 = 258,
|
||||
RETROK_KP3 = 259,
|
||||
RETROK_KP4 = 260,
|
||||
RETROK_KP5 = 261,
|
||||
RETROK_KP6 = 262,
|
||||
RETROK_KP7 = 263,
|
||||
RETROK_KP8 = 264,
|
||||
RETROK_KP9 = 265,
|
||||
RETROK_KP_PERIOD = 266,
|
||||
RETROK_KP_DIVIDE = 267,
|
||||
RETROK_KP_MULTIPLY = 268,
|
||||
RETROK_KP_MINUS = 269,
|
||||
RETROK_KP_PLUS = 270,
|
||||
RETROK_KP_ENTER = 271,
|
||||
RETROK_KP_EQUALS = 272,
|
||||
|
||||
RETROK_UP = 273,
|
||||
RETROK_DOWN = 274,
|
||||
RETROK_RIGHT = 275,
|
||||
RETROK_LEFT = 276,
|
||||
RETROK_INSERT = 277,
|
||||
RETROK_HOME = 278,
|
||||
RETROK_END = 279,
|
||||
RETROK_PAGEUP = 280,
|
||||
RETROK_PAGEDOWN = 281,
|
||||
|
||||
RETROK_F1 = 282,
|
||||
RETROK_F2 = 283,
|
||||
RETROK_F3 = 284,
|
||||
RETROK_F4 = 285,
|
||||
RETROK_F5 = 286,
|
||||
RETROK_F6 = 287,
|
||||
RETROK_F7 = 288,
|
||||
RETROK_F8 = 289,
|
||||
RETROK_F9 = 290,
|
||||
RETROK_F10 = 291,
|
||||
RETROK_F11 = 292,
|
||||
RETROK_F12 = 293,
|
||||
RETROK_F13 = 294,
|
||||
RETROK_F14 = 295,
|
||||
RETROK_F15 = 296,
|
||||
|
||||
RETROK_NUMLOCK = 300,
|
||||
RETROK_CAPSLOCK = 301,
|
||||
RETROK_SCROLLOCK = 302,
|
||||
RETROK_RSHIFT = 303,
|
||||
RETROK_LSHIFT = 304,
|
||||
RETROK_RCTRL = 305,
|
||||
RETROK_LCTRL = 306,
|
||||
RETROK_RALT = 307,
|
||||
RETROK_LALT = 308,
|
||||
RETROK_RMETA = 309,
|
||||
RETROK_LMETA = 310,
|
||||
RETROK_LSUPER = 311,
|
||||
RETROK_RSUPER = 312,
|
||||
RETROK_MODE = 313,
|
||||
RETROK_COMPOSE = 314,
|
||||
|
||||
RETROK_HELP = 315,
|
||||
RETROK_PRINT = 316,
|
||||
RETROK_SYSREQ = 317,
|
||||
RETROK_BREAK = 318,
|
||||
RETROK_MENU = 319,
|
||||
RETROK_POWER = 320,
|
||||
RETROK_EURO = 321,
|
||||
RETROK_UNDO = 322,
|
||||
|
||||
RETROK_LAST
|
||||
};
|
||||
|
||||
// Environment commands.
|
||||
#define RETRO_ENVIRONMENT_SET_ROTATION 1 // const unsigned * --
|
||||
// Sets screen rotation of graphics.
|
||||
// Is only implemented if rotation can be accelerated by hardware.
|
||||
// Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180, 270 degrees
|
||||
// counter-clockwise respectively.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_GET_OVERSCAN 2 // bool * --
|
||||
// Boolean value whether or not the implementation should use overscan, or crop away overscan.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_GET_CAN_DUPE 3 // bool * --
|
||||
// Boolean value whether or not frontend supports frame duping,
|
||||
// passing NULL to video frame callback.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_GET_VARIABLE 4 // struct retro_variable * --
|
||||
// Interface to aquire user-defined information from environment
|
||||
// that cannot feasibly be supported in a multi-system way.
|
||||
// Mostly used for obscure,
|
||||
// specific features that the user can tap into when neseccary.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_SET_VARIABLES 5 // const struct retro_variable * --
|
||||
// Allows an implementation to signal the environment
|
||||
// which variables it might want to check for later using GET_VARIABLE.
|
||||
// 'data' points to an array of retro_variable structs terminated by a { NULL, NULL } element.
|
||||
// retro_variable::value should contain a human readable description of the key.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_SET_MESSAGE 6 // const struct retro_message * --
|
||||
// Sets a message to be displayed in implementation-specific manner for a certain amount of 'frames'.
|
||||
// Should not be used for trivial messages, which should simply be logged to stderr.
|
||||
#define RETRO_ENVIRONMENT_SHUTDOWN 7 // N/A (NULL) --
|
||||
// Requests the frontend to shutdown.
|
||||
// Should only be used if game has a specific
|
||||
// way to shutdown the game from a menu item or similar.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8
|
||||
// const unsigned * --
|
||||
// Gives a hint to the frontend how demanding this implementation
|
||||
// is on a system. E.g. reporting a level of 2 means
|
||||
// this implementation should run decently on all frontends
|
||||
// of level 2 and up.
|
||||
//
|
||||
// It can be used by the frontend to potentially warn
|
||||
// about too demanding implementations.
|
||||
//
|
||||
// The levels are "floating", but roughly defined as:
|
||||
// 0: Low-powered embedded devices such as Raspberry Pi
|
||||
// 1: 6th generation consoles, such as Wii/Xbox 1, and phones, tablets, etc.
|
||||
// 2: 7th generation consoles, such as PS3/360, with sub-par CPUs.
|
||||
// 3: Modern desktop/laptops with reasonably powerful CPUs.
|
||||
// 4: High-end desktops with very powerful CPUs.
|
||||
//
|
||||
// This function can be called on a per-game basis,
|
||||
// as certain games an implementation can play might be
|
||||
// particularily demanding.
|
||||
// If called, it should be called in retro_load_game().
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9
|
||||
// const char ** --
|
||||
// Returns the "system" directory of the frontend.
|
||||
// This directory can be used to store system specific ROMs such as BIOSes, configuration data, etc.
|
||||
// The returned value can be NULL.
|
||||
// If so, no such directory is defined,
|
||||
// and it's up to the implementation to find a suitable directory.
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10
|
||||
// const enum retro_pixel_format * --
|
||||
// Sets the internal pixel format used by the implementation.
|
||||
// The default pixel format is RETRO_PIXEL_FORMAT_0RGB1555.
|
||||
// This pixel format however, is deprecated (see enum retro_pixel_format).
|
||||
// If the call returns false, the frontend does not support this pixel format.
|
||||
// This function should be called inside retro_load_game() or retro_get_system_av_info().
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11
|
||||
// const struct retro_input_descriptor * --
|
||||
// Sets an array of retro_input_descriptors.
|
||||
// It is up to the frontend to present this in a usable way.
|
||||
// The array is terminated by retro_input_descriptor::description being set to NULL.
|
||||
// This function can be called at any time, but it is recommended to call it as early as possible.
|
||||
|
||||
|
||||
enum retro_pixel_format
|
||||
{
|
||||
// 0RGB1555, native endian. 0 bit must be set to 0.
|
||||
// This pixel format is default for compatibility concerns only.
|
||||
// If a 15/16-bit pixel format is desired, consider using RGB565.
|
||||
RETRO_PIXEL_FORMAT_0RGB1555 = 0,
|
||||
|
||||
// XRGB8888, native endian. X bits are ignored.
|
||||
RETRO_PIXEL_FORMAT_XRGB8888 = 1,
|
||||
|
||||
// RGB565, native endian. This pixel format is the recommended format to use if a 15/16-bit format is desired
|
||||
// as it is the pixel format that is typically available on a wide range of low-power devices.
|
||||
// It is also natively supported in APIs like OpenGL ES.
|
||||
RETRO_PIXEL_FORMAT_RGB565 = 2
|
||||
};
|
||||
|
||||
struct retro_message
|
||||
{
|
||||
const char *msg; // Message to be displayed.
|
||||
unsigned frames; // Duration in frames of message.
|
||||
};
|
||||
|
||||
// Describes how the libretro implementation maps a libretro input bind
|
||||
// to its internal input system through a human readable string.
|
||||
// This string can be used to better let a user configure input.
|
||||
struct retro_input_descriptor
|
||||
{
|
||||
// Associates given parameters with a description.
|
||||
unsigned port;
|
||||
unsigned device;
|
||||
unsigned index;
|
||||
unsigned id;
|
||||
|
||||
const char *description; // Human readable description for parameters.
|
||||
// The pointer must remain valid until retro_unload_game() is called.
|
||||
};
|
||||
|
||||
struct retro_system_info
|
||||
{
|
||||
// All pointers are owned by libretro implementation, and pointers must remain valid until retro_deinit() is called.
|
||||
|
||||
const char *library_name; // Descriptive name of library. Should not contain any version numbers, etc.
|
||||
const char *library_version; // Descriptive version of core.
|
||||
|
||||
const char *valid_extensions; // A string listing probably rom extensions the core will be able to load, separated with pipe.
|
||||
// I.e. "bin|rom|iso".
|
||||
// Typically used for a GUI to filter out extensions.
|
||||
|
||||
bool need_fullpath; // If true, retro_load_game() is guaranteed to provide a valid pathname in retro_game_info::path.
|
||||
// ::data and ::size are both invalid.
|
||||
// If false, ::data and ::size are guaranteed to be valid, but ::path might not be valid.
|
||||
// This is typically set to true for libretro implementations that must load from file.
|
||||
// Implementations should strive for setting this to false, as it allows the frontend to perform patching, etc.
|
||||
|
||||
bool block_extract; // If true, the frontend is not allowed to extract any archives before loading the real ROM.
|
||||
// Necessary for certain libretro implementations that load games from zipped archives.
|
||||
};
|
||||
|
||||
struct retro_game_geometry
|
||||
{
|
||||
unsigned base_width; // Nominal video width of game.
|
||||
unsigned base_height; // Nominal video height of game.
|
||||
unsigned max_width; // Maximum possible width of game.
|
||||
unsigned max_height; // Maximum possible height of game.
|
||||
|
||||
float aspect_ratio; // Nominal aspect ratio of game. If aspect_ratio is <= 0.0,
|
||||
// an aspect ratio of base_width / base_height is assumed.
|
||||
// A frontend could override this setting if desired.
|
||||
};
|
||||
|
||||
struct retro_system_timing
|
||||
{
|
||||
double fps; // FPS of video content.
|
||||
double sample_rate; // Sampling rate of audio.
|
||||
};
|
||||
|
||||
struct retro_system_av_info
|
||||
{
|
||||
struct retro_game_geometry geometry;
|
||||
struct retro_system_timing timing;
|
||||
};
|
||||
|
||||
struct retro_variable
|
||||
{
|
||||
const char *key; // Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE.
|
||||
// If NULL, obtains the complete environment string if more complex parsing is necessary.
|
||||
// The environment string is formatted as key-value pairs delimited by semicolons as so:
|
||||
// "key1=value1;key2=value2;..."
|
||||
const char *value; // Value to be obtained. If key does not exist, it is set to NULL.
|
||||
};
|
||||
|
||||
struct retro_game_info
|
||||
{
|
||||
const char *path; // Path to game, UTF-8 encoded. Usually used as a reference.
|
||||
// May be NULL if rom was loaded from stdin or similar.
|
||||
// retro_system_info::need_fullpath guaranteed that this path is valid.
|
||||
const void *data; // Memory buffer of loaded game. Will be NULL if need_fullpath was set.
|
||||
size_t size; // Size of memory buffer.
|
||||
const char *meta; // String of implementation specific meta-data.
|
||||
};
|
||||
|
||||
// Callbacks
|
||||
//
|
||||
// Environment callback. Gives implementations a way of performing uncommon tasks. Extensible.
|
||||
typedef bool (*retro_environment_t)(unsigned cmd, void *data);
|
||||
|
||||
// Render a frame. Pixel format is 15-bit 0RGB1555 native endian unless changed (see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT).
|
||||
// Width and height specify dimensions of buffer.
|
||||
// Pitch specifices length in bytes between two lines in buffer.
|
||||
// For performance reasons, it is highly recommended to have a frame that is packed in memory, i.e. pitch == width * byte_per_pixel.
|
||||
// Certain graphic APIs, such as OpenGL ES, do not like textures that are not packed in memory.
|
||||
typedef void (*retro_video_refresh_t)(const void *data, unsigned width, unsigned height, size_t pitch);
|
||||
|
||||
// Renders a single audio frame. Should only be used if implementation generates a single sample at a time.
|
||||
// Format is signed 16-bit native endian.
|
||||
typedef void (*retro_audio_sample_t)(int16_t left, int16_t right);
|
||||
// Renders multiple audio frames in one go. One frame is defined as a sample of left and right channels, interleaved.
|
||||
// I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames.
|
||||
// Only one of the audio callbacks must ever be used.
|
||||
typedef size_t (*retro_audio_sample_batch_t)(const int16_t *data, size_t frames);
|
||||
|
||||
// Polls input.
|
||||
typedef void (*retro_input_poll_t)(void);
|
||||
// Queries for input for player 'port'. device will be masked with RETRO_DEVICE_MASK.
|
||||
// Specialization of devices such as RETRO_DEVICE_JOYPAD_MULTITAP that have been set with retro_set_controller_port_device()
|
||||
// will still use the higher level RETRO_DEVICE_JOYPAD to request input.
|
||||
typedef int16_t (*retro_input_state_t)(unsigned port, unsigned device, unsigned index, unsigned id);
|
||||
|
||||
// Sets callbacks. retro_set_environment() is guaranteed to be called before retro_init().
|
||||
// The rest of the set_* functions are guaranteed to have been called before the first call to retro_run() is made.
|
||||
void retro_set_environment(retro_environment_t);
|
||||
void retro_set_video_refresh(retro_video_refresh_t);
|
||||
void retro_set_audio_sample(retro_audio_sample_t);
|
||||
void retro_set_audio_sample_batch(retro_audio_sample_batch_t);
|
||||
void retro_set_input_poll(retro_input_poll_t);
|
||||
void retro_set_input_state(retro_input_state_t);
|
||||
|
||||
// Library global initialization/deinitialization.
|
||||
void retro_init(void);
|
||||
void retro_deinit(void);
|
||||
|
||||
// Must return RETRO_API_VERSION. Used to validate ABI compatibility when the API is revised.
|
||||
unsigned retro_api_version(void);
|
||||
|
||||
// Gets statically known system info. Pointers provided in *info must be statically allocated.
|
||||
// Can be called at any time, even before retro_init().
|
||||
void retro_get_system_info(struct retro_system_info *info);
|
||||
|
||||
// Gets information about system audio/video timings and geometry.
|
||||
// Can be called only after retro_load_game() has successfully completed.
|
||||
// NOTE: The implementation of this function might not initialize every variable if needed.
|
||||
// E.g. geom.aspect_ratio might not be initialized if core doesn't desire a particular aspect ratio.
|
||||
void retro_get_system_av_info(struct retro_system_av_info *info);
|
||||
|
||||
// Sets device to be used for player 'port'.
|
||||
void retro_set_controller_port_device(unsigned port, unsigned device);
|
||||
|
||||
// Resets the current game.
|
||||
void retro_reset(void);
|
||||
|
||||
// Runs the game for one video frame.
|
||||
// During retro_run(), input_poll callback must be called at least once.
|
||||
//
|
||||
// If a frame is not rendered for reasons where a game "dropped" a frame,
|
||||
// this still counts as a frame, and retro_run() should explicitly dupe a frame if GET_CAN_DUPE returns true.
|
||||
// In this case, the video callback can take a NULL argument for data.
|
||||
void retro_run(void);
|
||||
|
||||
// Returns the amount of data the implementation requires to serialize internal state (save states).
|
||||
// Beetween calls to retro_load_game() and retro_unload_game(), the returned size is never allowed to be larger than a previous returned value, to
|
||||
// ensure that the frontend can allocate a save state buffer once.
|
||||
size_t retro_serialize_size(void);
|
||||
|
||||
// Serializes internal state. If failed, or size is lower than retro_serialize_size(), it should return false, true otherwise.
|
||||
bool retro_serialize(void *data, size_t size);
|
||||
bool retro_unserialize(const void *data, size_t size);
|
||||
|
||||
void retro_cheat_reset(void);
|
||||
void retro_cheat_set(unsigned index, bool enabled, const char *code, const char *type);
|
||||
|
||||
// Loads a game.
|
||||
bool retro_load_game(const struct retro_game_info *game);
|
||||
|
||||
// Loads a "special" kind of game. Should not be used except in extreme cases.
|
||||
bool retro_load_game_special(
|
||||
unsigned game_type,
|
||||
const struct retro_game_info *info, size_t num_info
|
||||
);
|
||||
|
||||
// Unloads a currently loaded game.
|
||||
void retro_unload_game(void);
|
||||
|
||||
// Gets region of game.
|
||||
unsigned retro_get_region(void);
|
||||
|
||||
// Gets region of memory.
|
||||
void *retro_get_memory_data(unsigned id);
|
||||
size_t retro_get_memory_size(unsigned id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,87 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef BITMAP_FONT_H
|
||||
#define BITMAP_FONT_H
|
||||
|
||||
#include "gbint.h"
|
||||
|
||||
namespace bitmapfont {
|
||||
enum Char {
|
||||
NUL,
|
||||
N0, N1, N2, N3, N4, N5, N6, N7, N8, N9,
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M,
|
||||
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
||||
a, b, c, d, e, f, g, h, i, j, k, l, m,
|
||||
n, o, p, q, r, s, t, u, v, w, x, y, z,
|
||||
SPC
|
||||
};
|
||||
|
||||
enum { HEIGHT = 10 };
|
||||
enum { MAX_WIDTH = 9 };
|
||||
enum { NUMBER_WIDTH = 6 };
|
||||
|
||||
unsigned getWidth(const char *chars);
|
||||
|
||||
// struct Fill { void operator()(RandomAccessIterator dest, unsigned pitch) { fill pixels at dest } }
|
||||
template<class RandomAccessIterator, class Fill>
|
||||
void print(RandomAccessIterator dest, unsigned pitch, Fill fill, const char *chars);
|
||||
|
||||
void print(gambatte::uint_least32_t *dest, unsigned pitch, unsigned long color, const char *chars);
|
||||
void utoa(unsigned u, char *a);
|
||||
|
||||
// --- INTERFACE END ---
|
||||
|
||||
|
||||
|
||||
extern const unsigned char *const font[];
|
||||
|
||||
template<class RandomAccessIterator, class Fill>
|
||||
void print(RandomAccessIterator dest, const unsigned pitch, Fill fill, const char *chars) {
|
||||
while (const int character = *chars++) {
|
||||
RandomAccessIterator dst = dest;
|
||||
const unsigned char *s = font[character];
|
||||
|
||||
const unsigned width = *s >> 4;
|
||||
unsigned h = *s++ & 0xF;
|
||||
|
||||
while (h--) {
|
||||
RandomAccessIterator d = dst;
|
||||
|
||||
unsigned line = *s++;
|
||||
|
||||
if (width > 8)
|
||||
line |= *s++ << 8;
|
||||
|
||||
while (line) {
|
||||
if (line & 1)
|
||||
fill(d, pitch);
|
||||
|
||||
line >>= 1;
|
||||
++d;
|
||||
}
|
||||
|
||||
dst += pitch;
|
||||
}
|
||||
|
||||
dest += width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,104 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef CPU_H
|
||||
#define CPU_H
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class CPU {
|
||||
Memory memory;
|
||||
|
||||
unsigned long cycleCounter_;
|
||||
|
||||
unsigned short PC_;
|
||||
unsigned short SP;
|
||||
|
||||
unsigned HF1, HF2, ZF, CF;
|
||||
|
||||
unsigned char A_, B, C, D, E, /*F,*/ H, L;
|
||||
|
||||
bool skip;
|
||||
|
||||
void process(unsigned long cycles);
|
||||
|
||||
public:
|
||||
|
||||
CPU();
|
||||
// void halt();
|
||||
|
||||
// unsigned interrupt(unsigned address, unsigned cycleCounter);
|
||||
|
||||
long runFor(unsigned long cycles);
|
||||
void setStatePtrs(SaveState &state);
|
||||
void saveState(SaveState &state);
|
||||
void loadState(const SaveState &state);
|
||||
|
||||
//void loadSavedata() { memory.loadSavedata(); }
|
||||
//void saveSavedata() { memory.saveSavedata(); }
|
||||
void *savedata_ptr() { return memory.savedata_ptr(); }
|
||||
unsigned savedata_size() { return memory.savedata_size(); }
|
||||
void *rtcdata_ptr() { return memory.rtcdata_ptr(); }
|
||||
unsigned rtcdata_size() { return memory.rtcdata_size(); }
|
||||
|
||||
void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) {
|
||||
memory.setVideoBuffer(videoBuf, pitch);
|
||||
}
|
||||
|
||||
void setInputGetter(InputGetter *getInput) {
|
||||
memory.setInputGetter(getInput);
|
||||
}
|
||||
|
||||
void setSaveDir(const std::string &sdir) {
|
||||
memory.setSaveDir(sdir);
|
||||
}
|
||||
|
||||
//const std::string saveBasePath() const {
|
||||
// return memory.saveBasePath();
|
||||
//}
|
||||
|
||||
void setOsdElement(std::auto_ptr<OsdElement> osdElement) {
|
||||
memory.setOsdElement(osdElement);
|
||||
}
|
||||
|
||||
LoadRes load(std::string const &romfile, bool forceDmg, bool multicartCompat) {
|
||||
return memory.loadROM(romfile, forceDmg, multicartCompat);
|
||||
}
|
||||
|
||||
//bool loaded() const { return memory.loaded(); }
|
||||
char const * romTitle() const { return memory.romTitle(); }
|
||||
PakInfo const pakInfo(bool multicartCompat) const { return memory.pakInfo(multicartCompat); }
|
||||
|
||||
void setSoundBuffer(uint_least32_t *const buf) { memory.setSoundBuffer(buf); }
|
||||
unsigned fillSoundBuffer() { return memory.fillSoundBuffer(cycleCounter_); }
|
||||
|
||||
bool isCgb() const { return memory.isCgb(); }
|
||||
|
||||
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) {
|
||||
memory.setDmgPaletteColor(palNum, colorNum, rgb32);
|
||||
}
|
||||
|
||||
void setGameGenie(const std::string &codes) { memory.setGameGenie(codes); }
|
||||
void setGameShark(const std::string &codes) { memory.setGameShark(codes); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,217 +0,0 @@
|
||||
/***************************************************************************
|
||||
Copyright (C) 2007 by Nach
|
||||
http://nsrt.edgeemu.com
|
||||
|
||||
Copyright (C) 2007-2011 by Sindre Aamås
|
||||
sinamas@users.sourceforge.net
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License version 2 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 2 along with this program; if not, write to the
|
||||
Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
***************************************************************************/
|
||||
#include "stdfile.h"
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
|
||||
namespace zlib {
|
||||
#include "unzip/unzip.h"
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class ZipFile : public gambatte::File {
|
||||
private:
|
||||
std::size_t fsize, count;
|
||||
void *zipfile;
|
||||
bool zip_sub_open;
|
||||
|
||||
void zip(const char *filename);
|
||||
|
||||
public:
|
||||
ZipFile(const char *filename);
|
||||
virtual ~ZipFile();
|
||||
virtual void rewind();
|
||||
bool is_open() const;
|
||||
virtual void close();
|
||||
virtual std::size_t size() const { return fsize; };
|
||||
virtual void read(char *buffer, std::size_t amount);
|
||||
std::size_t gcount() const { return count; }
|
||||
virtual bool fail() const { return !is_open(); }
|
||||
};
|
||||
|
||||
using namespace std;
|
||||
using namespace zlib;
|
||||
|
||||
static const unsigned int MAX_FILE_NAME = 512;
|
||||
|
||||
ZipFile::ZipFile(const char *filename) : fsize(0), count(0)
|
||||
{
|
||||
zip(filename);
|
||||
}
|
||||
|
||||
void ZipFile::zip(const char *filename)
|
||||
{
|
||||
zipfile = unzOpen(filename);
|
||||
if (zipfile)
|
||||
{
|
||||
zip_sub_open = false;
|
||||
|
||||
unz_file_info cFileInfo;
|
||||
char ourFile[MAX_FILE_NAME] = { '\n' };
|
||||
|
||||
for (int cFile = unzGoToFirstFile((unzFile)zipfile); cFile == UNZ_OK; cFile = unzGoToNextFile((unzFile)zipfile))
|
||||
{
|
||||
//Temporary char array for file name
|
||||
char cFileName[MAX_FILE_NAME];
|
||||
|
||||
//Gets info on current file, and places it in cFileInfo
|
||||
unzGetCurrentFileInfo((unzFile)zipfile, &cFileInfo, cFileName, MAX_FILE_NAME, 0, 0, 0, 0);
|
||||
|
||||
//Check for largest file which should be the ROM
|
||||
if ((size_t)cFileInfo.uncompressed_size > fsize)
|
||||
{
|
||||
strcpy(ourFile, cFileName);
|
||||
fsize = (size_t)cFileInfo.uncompressed_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (ourFile[0] != '\n')
|
||||
{
|
||||
//Sets current file to the file we liked before
|
||||
unzLocateFile((unzFile)zipfile, ourFile, 1);
|
||||
|
||||
if (unzOpenCurrentFile((unzFile)zipfile) == UNZ_OK)
|
||||
{
|
||||
zip_sub_open = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!zip_sub_open)
|
||||
{
|
||||
unzClose((unzFile)zipfile);
|
||||
zipfile = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ZipFile::~ZipFile()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void ZipFile::rewind()
|
||||
{
|
||||
if (is_open())
|
||||
{
|
||||
unzCloseCurrentFile((unzFile)zipfile);
|
||||
unzOpenCurrentFile((unzFile)zipfile);
|
||||
}
|
||||
}
|
||||
|
||||
bool ZipFile::is_open() const
|
||||
{
|
||||
return(zipfile && zip_sub_open);
|
||||
}
|
||||
|
||||
void ZipFile::close()
|
||||
{
|
||||
if (is_open())
|
||||
{
|
||||
unzOpenCurrentFile((unzFile)zipfile);
|
||||
unzClose((unzFile)zipfile);
|
||||
zipfile = 0;
|
||||
zip_sub_open = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ZipFile::read(char *buffer, size_t amount)
|
||||
{
|
||||
if (is_open())
|
||||
{
|
||||
count = (size_t)unzReadCurrentFile((unzFile)zipfile, buffer, amount);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
class GzFile : public gambatte::File {
|
||||
gzFile file_;
|
||||
std::size_t fsize_;
|
||||
|
||||
void close();
|
||||
GzFile(const GzFile &);
|
||||
GzFile& operator=(const GzFile &);
|
||||
public:
|
||||
explicit GzFile(const char *filename)
|
||||
: file_(gzopen(filename, "rb")), fsize_(0)
|
||||
{
|
||||
if (file_) {
|
||||
char buf[256];
|
||||
int ret;
|
||||
|
||||
while ((ret = gzread(file_, buf, sizeof buf)) > 0)
|
||||
fsize_ += ret;
|
||||
|
||||
if (ret < 0) {
|
||||
close();
|
||||
fsize_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
rewind();
|
||||
}
|
||||
|
||||
virtual ~GzFile() { close(); }
|
||||
|
||||
virtual void rewind() {
|
||||
if (file_ && gzrewind(file_) < 0)
|
||||
close();
|
||||
}
|
||||
|
||||
virtual std::size_t size() const { return fsize_; };
|
||||
|
||||
virtual void read(char *buffer, std::size_t amount) {
|
||||
if (file_ && gzread(file_, buffer, amount) < 0)
|
||||
close();
|
||||
}
|
||||
|
||||
virtual bool fail() const { return !file_; }
|
||||
};
|
||||
|
||||
void GzFile::close() {
|
||||
if (file_) {
|
||||
gzclose(file_);
|
||||
file_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Avoid checking magic header values, because there are no values that cannot occur in a GB ROM.
|
||||
std::auto_ptr<gambatte::File> gambatte::newFileInstance(const std::string &filepath) {
|
||||
const std::size_t extpos = filepath.rfind(".");
|
||||
|
||||
if (extpos != std::string::npos) {
|
||||
const std::string &ext = filepath.substr(extpos + 1);
|
||||
|
||||
if (ext.length() == 3 && std::tolower(ext[0]) == 'z' && std::tolower(ext[1]) == 'i'&& std::tolower(ext[2]) == 'p')
|
||||
return std::auto_ptr<File>(new ZipFile(filepath.c_str()));
|
||||
|
||||
if (!ext.empty() && std::tolower(ext[ext.length() - 1]) == 'z')
|
||||
return std::auto_ptr<File>(new GzFile(filepath.c_str()));
|
||||
}
|
||||
|
||||
return std::auto_ptr<File>(new StdFile(filepath.c_str()));
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/* crypt.h -- base code for crypt/uncrypt ZIPfile
|
||||
|
||||
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
|
||||
This code is a modified version of crypting code in Infozip distribution
|
||||
|
||||
The encryption/decryption parts of this source code (as opposed to the
|
||||
non-echoing password parts) were originally written in Europe. The
|
||||
whole source package can be freely distributed, including from the USA.
|
||||
(Prior to January 2000, re-export from the US was a violation of US law.)
|
||||
|
||||
This encryption code is a direct transcription of the algorithm from
|
||||
Roger Schlafly, described by Phil Katz in the file appnote.txt. This
|
||||
file (appnote.txt) is distributed with the PKZIP program (even in the
|
||||
version without encryption capabilities).
|
||||
|
||||
If you don't need crypting in your application, just define symbols
|
||||
NOCRYPT and NOUNCRYPT.
|
||||
|
||||
This code support the "Traditional PKWARE Encryption".
|
||||
|
||||
The new AES encryption added on Zip format by Winzip (see the page
|
||||
http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
|
||||
Encryption is not supported.
|
||||
*/
|
||||
|
||||
#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
|
||||
|
||||
/***********************************************************************
|
||||
* Return the next byte in the pseudo-random sequence
|
||||
*/
|
||||
static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab)
|
||||
{
|
||||
unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
|
||||
* unpredictable manner on 16-bit systems; not a problem
|
||||
* with any known compiler so far, though */
|
||||
|
||||
temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
|
||||
return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Update the encryption keys with the next byte of plain text
|
||||
*/
|
||||
static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c)
|
||||
{
|
||||
(*(pkeys+0)) = CRC32((*(pkeys+0)), c);
|
||||
(*(pkeys+1)) += (*(pkeys+0)) & 0xff;
|
||||
(*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
|
||||
{
|
||||
register int keyshift = (int)((*(pkeys+1)) >> 24);
|
||||
(*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Initialize the encryption keys and the random header according to
|
||||
* the given password.
|
||||
*/
|
||||
static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab)
|
||||
{
|
||||
*(pkeys+0) = 305419896L;
|
||||
*(pkeys+1) = 591751049L;
|
||||
*(pkeys+2) = 878082192L;
|
||||
while (*passwd != '\0') {
|
||||
update_keys(pkeys,pcrc_32_tab,(int)*passwd);
|
||||
passwd++;
|
||||
}
|
||||
}
|
||||
|
||||
#define zdecode(pkeys,pcrc_32_tab,c) \
|
||||
(update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
|
||||
|
||||
#define zencode(pkeys,pcrc_32_tab,c,t) \
|
||||
(t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
|
||||
|
||||
#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
|
||||
|
||||
#define RAND_HEAD_LEN 12
|
||||
/* "last resort" source for second part of crypt seed pattern */
|
||||
# ifndef ZCR_SEED2
|
||||
# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
|
||||
# endif
|
||||
|
||||
static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting)
|
||||
const char *passwd; /* password string */
|
||||
unsigned char *buf; /* where to write header */
|
||||
int bufSize;
|
||||
unsigned long* pkeys;
|
||||
const unsigned long* pcrc_32_tab;
|
||||
unsigned long crcForCrypting;
|
||||
{
|
||||
int n; /* index in random header */
|
||||
int t; /* temporary */
|
||||
int c; /* random byte */
|
||||
unsigned char header[RAND_HEAD_LEN-2]; /* random header */
|
||||
static unsigned calls = 0; /* ensure different random header each time */
|
||||
|
||||
if (bufSize<RAND_HEAD_LEN)
|
||||
return 0;
|
||||
|
||||
/* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
|
||||
* output of rand() to get less predictability, since rand() is
|
||||
* often poorly implemented.
|
||||
*/
|
||||
if (++calls == 1)
|
||||
{
|
||||
srand((unsigned)(time(NULL) ^ ZCR_SEED2));
|
||||
}
|
||||
init_keys(passwd, pkeys, pcrc_32_tab);
|
||||
for (n = 0; n < RAND_HEAD_LEN-2; n++)
|
||||
{
|
||||
c = (rand() >> 7) & 0xff;
|
||||
header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
|
||||
}
|
||||
/* Encrypt random header (last two bytes is high word of crc) */
|
||||
init_keys(passwd, pkeys, pcrc_32_tab);
|
||||
for (n = 0; n < RAND_HEAD_LEN-2; n++)
|
||||
{
|
||||
buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
|
||||
}
|
||||
buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
|
||||
buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,177 +0,0 @@
|
||||
/* ioapi.c -- IO base function header for compress/uncompress .zip
|
||||
files using zlib + zip or unzip API
|
||||
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <zlib.h>
|
||||
#include "ioapi.h"
|
||||
|
||||
|
||||
|
||||
/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
|
||||
|
||||
#ifndef SEEK_CUR
|
||||
#define SEEK_CUR 1
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_END
|
||||
#define SEEK_END 2
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_SET
|
||||
#define SEEK_SET 0
|
||||
#endif
|
||||
|
||||
voidpf ZCALLBACK fopen_file_func OF((
|
||||
voidpf opaque,
|
||||
const char* filename,
|
||||
int mode));
|
||||
|
||||
uLong ZCALLBACK fread_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream,
|
||||
void* buf,
|
||||
uLong size));
|
||||
|
||||
uLong ZCALLBACK fwrite_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream,
|
||||
const void* buf,
|
||||
uLong size));
|
||||
|
||||
long ZCALLBACK ftell_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream));
|
||||
|
||||
long ZCALLBACK fseek_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream,
|
||||
uLong offset,
|
||||
int origin));
|
||||
|
||||
int ZCALLBACK fclose_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream));
|
||||
|
||||
int ZCALLBACK ferror_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream));
|
||||
|
||||
|
||||
voidpf ZCALLBACK fopen_file_func (opaque, filename, mode)
|
||||
voidpf opaque;
|
||||
const char* filename;
|
||||
int mode;
|
||||
{
|
||||
FILE* file = NULL;
|
||||
const char* mode_fopen = NULL;
|
||||
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
|
||||
mode_fopen = "rb";
|
||||
else
|
||||
if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
|
||||
mode_fopen = "r+b";
|
||||
else
|
||||
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
|
||||
mode_fopen = "wb";
|
||||
|
||||
if ((filename!=NULL) && (mode_fopen != NULL))
|
||||
file = fopen(filename, mode_fopen);
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
uLong ZCALLBACK fread_file_func (opaque, stream, buf, size)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
void* buf;
|
||||
uLong size;
|
||||
{
|
||||
uLong ret;
|
||||
ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
const void* buf;
|
||||
uLong size;
|
||||
{
|
||||
uLong ret;
|
||||
ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
long ZCALLBACK ftell_file_func (opaque, stream)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
{
|
||||
long ret;
|
||||
ret = ftell((FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
long ZCALLBACK fseek_file_func (opaque, stream, offset, origin)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
uLong offset;
|
||||
int origin;
|
||||
{
|
||||
int fseek_origin=0;
|
||||
long ret;
|
||||
switch (origin)
|
||||
{
|
||||
case ZLIB_FILEFUNC_SEEK_CUR :
|
||||
fseek_origin = SEEK_CUR;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_END :
|
||||
fseek_origin = SEEK_END;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_SET :
|
||||
fseek_origin = SEEK_SET;
|
||||
break;
|
||||
default: return -1;
|
||||
}
|
||||
ret = 0;
|
||||
fseek((FILE *)stream, offset, fseek_origin);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ZCALLBACK fclose_file_func (opaque, stream)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
{
|
||||
int ret;
|
||||
ret = fclose((FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ZCALLBACK ferror_file_func (opaque, stream)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
{
|
||||
int ret;
|
||||
ret = ferror((FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fill_fopen_filefunc (pzlib_filefunc_def)
|
||||
zlib_filefunc_def* pzlib_filefunc_def;
|
||||
{
|
||||
pzlib_filefunc_def->zopen_file = fopen_file_func;
|
||||
pzlib_filefunc_def->zread_file = fread_file_func;
|
||||
pzlib_filefunc_def->zwrite_file = fwrite_file_func;
|
||||
pzlib_filefunc_def->ztell_file = ftell_file_func;
|
||||
pzlib_filefunc_def->zseek_file = fseek_file_func;
|
||||
pzlib_filefunc_def->zclose_file = fclose_file_func;
|
||||
pzlib_filefunc_def->zerror_file = ferror_file_func;
|
||||
pzlib_filefunc_def->opaque = NULL;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/* ioapi.h -- IO base function header for compress/uncompress .zip
|
||||
files using zlib + zip or unzip API
|
||||
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
*/
|
||||
|
||||
#ifndef _ZLIBIOAPI_H
|
||||
#define _ZLIBIOAPI_H
|
||||
|
||||
|
||||
#define ZLIB_FILEFUNC_SEEK_CUR (1)
|
||||
#define ZLIB_FILEFUNC_SEEK_END (2)
|
||||
#define ZLIB_FILEFUNC_SEEK_SET (0)
|
||||
|
||||
#define ZLIB_FILEFUNC_MODE_READ (1)
|
||||
#define ZLIB_FILEFUNC_MODE_WRITE (2)
|
||||
#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
|
||||
|
||||
#define ZLIB_FILEFUNC_MODE_EXISTING (4)
|
||||
#define ZLIB_FILEFUNC_MODE_CREATE (8)
|
||||
|
||||
|
||||
#ifndef ZCALLBACK
|
||||
|
||||
#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
|
||||
#define ZCALLBACK CALLBACK
|
||||
#else
|
||||
#define ZCALLBACK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
|
||||
typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
|
||||
typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
|
||||
typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
|
||||
typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
|
||||
typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
|
||||
typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
|
||||
|
||||
typedef struct zlib_filefunc_def_s
|
||||
{
|
||||
open_file_func zopen_file;
|
||||
read_file_func zread_file;
|
||||
write_file_func zwrite_file;
|
||||
tell_file_func ztell_file;
|
||||
seek_file_func zseek_file;
|
||||
close_file_func zclose_file;
|
||||
testerror_file_func zerror_file;
|
||||
voidpf opaque;
|
||||
} zlib_filefunc_def;
|
||||
|
||||
|
||||
|
||||
void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
|
||||
|
||||
#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size))
|
||||
#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size))
|
||||
#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream))
|
||||
#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode))
|
||||
#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream))
|
||||
#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,358 +0,0 @@
|
||||
/* unzip.h -- IO for uncompress .zip files using zlib
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
|
||||
This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
|
||||
WinZip, InfoZip tools and compatible.
|
||||
|
||||
Multi volume ZipFile (span) are not supported.
|
||||
Encryption compatible with pkzip 2.04g only supported
|
||||
Old compressions used by old PKZip 1.x are not supported
|
||||
|
||||
|
||||
I WAIT FEEDBACK at mail info@winimage.com
|
||||
Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
|
||||
|
||||
Condition of use and distribution are the same than zlib :
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/* for more info about .ZIP format, see
|
||||
http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
|
||||
http://www.info-zip.org/pub/infozip/doc/
|
||||
PkWare has also a specification at :
|
||||
ftp://ftp.pkware.com/probdesc.zip
|
||||
*/
|
||||
|
||||
#ifndef _unz_H
|
||||
#define _unz_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _ZLIB_H
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef OF
|
||||
#define OF(args) args
|
||||
#endif
|
||||
|
||||
#ifndef _ZLIBIOAPI_H
|
||||
#include "ioapi.h"
|
||||
#endif
|
||||
|
||||
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
|
||||
/* like the STRICT of WIN32, we define a pointer that cannot be converted
|
||||
from (void*) without cast */
|
||||
typedef struct TagunzFile__ { int unused; } unzFile__;
|
||||
typedef unzFile__ *unzFile;
|
||||
#else
|
||||
typedef voidp unzFile;
|
||||
#endif
|
||||
|
||||
|
||||
#define UNZ_OK (0)
|
||||
#define UNZ_END_OF_LIST_OF_FILE (-100)
|
||||
#define UNZ_ERRNO (Z_ERRNO)
|
||||
#define UNZ_EOF (0)
|
||||
#define UNZ_PARAMERROR (-102)
|
||||
#define UNZ_BADZIPFILE (-103)
|
||||
#define UNZ_INTERNALERROR (-104)
|
||||
#define UNZ_CRCERROR (-105)
|
||||
|
||||
/* tm_unz contain date/time info */
|
||||
typedef struct tm_unz_s
|
||||
{
|
||||
uInt tm_sec; /* seconds after the minute - [0,59] */
|
||||
uInt tm_min; /* minutes after the hour - [0,59] */
|
||||
uInt tm_hour; /* hours since midnight - [0,23] */
|
||||
uInt tm_mday; /* day of the month - [1,31] */
|
||||
uInt tm_mon; /* months since January - [0,11] */
|
||||
uInt tm_year; /* years - [1980..2044] */
|
||||
} tm_unz;
|
||||
|
||||
/* unz_global_info structure contain global data about the ZIPfile
|
||||
These data comes from the end of central dir */
|
||||
typedef struct unz_global_info_s
|
||||
{
|
||||
uLong number_entry; /* total number of entries in
|
||||
the central dir on this disk */
|
||||
uLong size_comment; /* size of the global comment of the zipfile */
|
||||
} unz_global_info;
|
||||
|
||||
|
||||
/* unz_file_info contain information about a file in the zipfile */
|
||||
typedef struct unz_file_info_s
|
||||
{
|
||||
uLong version; /* version made by 2 bytes */
|
||||
uLong version_needed; /* version needed to extract 2 bytes */
|
||||
uLong flag; /* general purpose bit flag 2 bytes */
|
||||
uLong compression_method; /* compression method 2 bytes */
|
||||
uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
|
||||
uLong crc; /* crc-32 4 bytes */
|
||||
uLong compressed_size; /* compressed size 4 bytes */
|
||||
uLong uncompressed_size; /* uncompressed size 4 bytes */
|
||||
uLong size_filename; /* filename length 2 bytes */
|
||||
uLong size_file_extra; /* extra field length 2 bytes */
|
||||
uLong size_file_comment; /* file comment length 2 bytes */
|
||||
|
||||
uLong disk_num_start; /* disk number start 2 bytes */
|
||||
uLong internal_fa; /* internal file attributes 2 bytes */
|
||||
uLong external_fa; /* external file attributes 4 bytes */
|
||||
|
||||
tm_unz tmu_date;
|
||||
} unz_file_info;
|
||||
|
||||
extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
|
||||
const char* fileName2,
|
||||
int iCaseSensitivity));
|
||||
/*
|
||||
Compare two filename (fileName1,fileName2).
|
||||
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
|
||||
If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
|
||||
or strcasecmp)
|
||||
If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
|
||||
(like 1 on Unix, 2 on Windows)
|
||||
*/
|
||||
|
||||
|
||||
extern unzFile ZEXPORT unzOpen OF((const char *path));
|
||||
/*
|
||||
Open a Zip file. path contain the full pathname (by example,
|
||||
on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
|
||||
"zlib/zlib113.zip".
|
||||
If the zipfile cannot be opened (file don't exist or in not valid), the
|
||||
return value is NULL.
|
||||
Else, the return value is a unzFile Handle, usable with other function
|
||||
of this unzip package.
|
||||
*/
|
||||
|
||||
extern unzFile ZEXPORT unzOpen2 OF((const char *path,
|
||||
zlib_filefunc_def* pzlib_filefunc_def));
|
||||
/*
|
||||
Open a Zip file, like unzOpen, but provide a set of file low level API
|
||||
for read/write the zip file (see ioapi.h)
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzClose OF((unzFile file));
|
||||
/*
|
||||
Close a ZipFile opened with unzipOpen.
|
||||
If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
|
||||
these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
|
||||
return UNZ_OK if there is no problem. */
|
||||
|
||||
extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
|
||||
unz_global_info *pglobal_info));
|
||||
/*
|
||||
Write info about the ZipFile in the *pglobal_info structure.
|
||||
No preparation of the structure is needed
|
||||
return UNZ_OK if there is no problem. */
|
||||
|
||||
|
||||
extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
|
||||
char *szComment,
|
||||
uLong uSizeBuf));
|
||||
/*
|
||||
Get the global comment string of the ZipFile, in the szComment buffer.
|
||||
uSizeBuf is the size of the szComment buffer.
|
||||
return the number of byte copied or an error code <0
|
||||
*/
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
/* Unzip package allow you browse the directory of the zipfile */
|
||||
|
||||
extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
|
||||
/*
|
||||
Set the current file of the zipfile to the first file.
|
||||
return UNZ_OK if there is no problem
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzGoToNextFile OF((unzFile file));
|
||||
/*
|
||||
Set the current file of the zipfile to the next file.
|
||||
return UNZ_OK if there is no problem
|
||||
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzLocateFile OF((unzFile file,
|
||||
const char *szFileName,
|
||||
int iCaseSensitivity));
|
||||
/*
|
||||
Try locate the file szFileName in the zipfile.
|
||||
For the iCaseSensitivity signification, see unzStringFileNameCompare
|
||||
|
||||
return value :
|
||||
UNZ_OK if the file is found. It becomes the current file.
|
||||
UNZ_END_OF_LIST_OF_FILE if the file is not found
|
||||
*/
|
||||
|
||||
|
||||
/* ****************************************** */
|
||||
/* Ryan supplied functions */
|
||||
/* unz_file_info contain information about a file in the zipfile */
|
||||
typedef struct unz_file_pos_s
|
||||
{
|
||||
uLong pos_in_zip_directory; /* offset in zip file directory */
|
||||
uLong num_of_file; /* # of file */
|
||||
} unz_file_pos;
|
||||
|
||||
extern int ZEXPORT unzGetFilePos(
|
||||
unzFile file,
|
||||
unz_file_pos* file_pos);
|
||||
|
||||
extern int ZEXPORT unzGoToFilePos(
|
||||
unzFile file,
|
||||
unz_file_pos* file_pos);
|
||||
|
||||
/* ****************************************** */
|
||||
|
||||
extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
|
||||
unz_file_info *pfile_info,
|
||||
char *szFileName,
|
||||
uLong fileNameBufferSize,
|
||||
void *extraField,
|
||||
uLong extraFieldBufferSize,
|
||||
char *szComment,
|
||||
uLong commentBufferSize));
|
||||
/*
|
||||
Get Info about the current file
|
||||
if pfile_info!=NULL, the *pfile_info structure will contain somes info about
|
||||
the current file
|
||||
if szFileName!=NULL, the filemane string will be copied in szFileName
|
||||
(fileNameBufferSize is the size of the buffer)
|
||||
if extraField!=NULL, the extra field information will be copied in extraField
|
||||
(extraFieldBufferSize is the size of the buffer).
|
||||
This is the Central-header version of the extra field
|
||||
if szComment!=NULL, the comment string of the file will be copied in szComment
|
||||
(commentBufferSize is the size of the buffer)
|
||||
*/
|
||||
|
||||
/***************************************************************************/
|
||||
/* for reading the content of the current zipfile, you can open it, read data
|
||||
from it, and close it (you can close it before reading all the file)
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
|
||||
/*
|
||||
Open for reading data the current file in the zipfile.
|
||||
If there is no error, the return value is UNZ_OK.
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,
|
||||
const char* password));
|
||||
/*
|
||||
Open for reading data the current file in the zipfile.
|
||||
password is a crypting password
|
||||
If there is no error, the return value is UNZ_OK.
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
|
||||
int* method,
|
||||
int* level,
|
||||
int raw));
|
||||
/*
|
||||
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
|
||||
if raw==1
|
||||
*method will receive method of compression, *level will receive level of
|
||||
compression
|
||||
note : you can set level parameter as NULL (if you did not want known level,
|
||||
but you CANNOT set method parameter as NULL
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
|
||||
int* method,
|
||||
int* level,
|
||||
int raw,
|
||||
const char* password));
|
||||
/*
|
||||
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
|
||||
if raw==1
|
||||
*method will receive method of compression, *level will receive level of
|
||||
compression
|
||||
note : you can set level parameter as NULL (if you did not want known level,
|
||||
but you CANNOT set method parameter as NULL
|
||||
*/
|
||||
|
||||
|
||||
extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
|
||||
/*
|
||||
Close the file in zip opened with unzOpenCurrentFile
|
||||
Return UNZ_CRCERROR if all the file was read but the CRC is not good
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
|
||||
voidp buf,
|
||||
unsigned len));
|
||||
/*
|
||||
Read bytes from the current file (opened by unzOpenCurrentFile)
|
||||
buf contain buffer where data must be copied
|
||||
len the size of buf.
|
||||
|
||||
return the number of byte copied if somes bytes are copied
|
||||
return 0 if the end of file was reached
|
||||
return <0 with error code if there is an error
|
||||
(UNZ_ERRNO for IO error, or zLib error for uncompress error)
|
||||
*/
|
||||
|
||||
extern z_off_t ZEXPORT unztell OF((unzFile file));
|
||||
/*
|
||||
Give the current position in uncompressed data
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzeof OF((unzFile file));
|
||||
/*
|
||||
return 1 if the end of file was reached, 0 elsewhere
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
|
||||
voidp buf,
|
||||
unsigned len));
|
||||
/*
|
||||
Read extra field from the current file (opened by unzOpenCurrentFile)
|
||||
This is the local-header version of the extra field (sometimes, there is
|
||||
more info in the local-header version than in the central-header)
|
||||
|
||||
if buf==NULL, it return the size of the local extra field
|
||||
|
||||
if buf!=NULL, len is the size of the buffer, the extra header is copied in
|
||||
buf.
|
||||
the return value is the number of bytes copied in buf, or (if <0)
|
||||
the error code
|
||||
*/
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/* Get the current file offset */
|
||||
extern uLong ZEXPORT unzGetOffset (unzFile file);
|
||||
|
||||
/* Set the current file offset */
|
||||
extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _unz_H */
|
||||
@@ -1,208 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "gambatte.h"
|
||||
#include "cpu.h"
|
||||
#include "savestate.h"
|
||||
#include "statesaver.h"
|
||||
#include "initstate.h"
|
||||
#include "state_osd_elements.h"
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
|
||||
//static const std::string itos(const int i) {
|
||||
// std::stringstream ss;
|
||||
// ss << i;
|
||||
// return ss.str();
|
||||
//}
|
||||
//
|
||||
//static const std::string statePath(const std::string &basePath, const int stateNo) {
|
||||
// return basePath + "_" + itos(stateNo) + ".gqs";
|
||||
//}
|
||||
|
||||
namespace gambatte {
|
||||
struct GB::Priv {
|
||||
CPU cpu;
|
||||
int stateNo;
|
||||
unsigned loadflags;
|
||||
|
||||
Priv() : stateNo(1), loadflags(0) {}
|
||||
};
|
||||
|
||||
GB::GB() : p_(new Priv) {}
|
||||
|
||||
GB::~GB() {
|
||||
// if (p_->cpu.loaded())
|
||||
// p_->cpu.saveSavedata();
|
||||
|
||||
delete p_;
|
||||
}
|
||||
|
||||
long GB::runFor(gambatte::uint_least32_t *const videoBuf, const int pitch,
|
||||
gambatte::uint_least32_t *const soundBuf, unsigned &samples) {
|
||||
//if (!p_->cpu.loaded()) {
|
||||
// samples = 0;
|
||||
// return -1;
|
||||
//}
|
||||
|
||||
p_->cpu.setVideoBuffer(videoBuf, pitch);
|
||||
p_->cpu.setSoundBuffer(soundBuf);
|
||||
const long cyclesSinceBlit = p_->cpu.runFor(samples * 2);
|
||||
samples = p_->cpu.fillSoundBuffer();
|
||||
|
||||
return cyclesSinceBlit < 0 ? cyclesSinceBlit : static_cast<long>(samples) - (cyclesSinceBlit >> 1);
|
||||
}
|
||||
|
||||
void GB::reset() {
|
||||
//if (p_->cpu.loaded()) {
|
||||
// p_->cpu.saveSavedata();
|
||||
|
||||
SaveState state;
|
||||
p_->cpu.setStatePtrs(state);
|
||||
setInitState(state, p_->cpu.isCgb(), p_->loadflags & GBA_CGB);
|
||||
p_->cpu.loadState(state);
|
||||
//p_->cpu.loadSavedata();
|
||||
//}
|
||||
}
|
||||
|
||||
void GB::setInputGetter(InputGetter *getInput) {
|
||||
p_->cpu.setInputGetter(getInput);
|
||||
}
|
||||
|
||||
//void GB::setSaveDir(const std::string &sdir) {
|
||||
// p_->cpu.setSaveDir(sdir);
|
||||
//}
|
||||
|
||||
LoadRes GB::load(std::string const &romfile, unsigned const flags) {
|
||||
//if (p_->cpu.loaded())
|
||||
// p_->cpu.saveSavedata();
|
||||
|
||||
LoadRes const loadres = p_->cpu.load(romfile, flags & FORCE_DMG, flags & MULTICART_COMPAT);
|
||||
|
||||
if (loadres == LOADRES_OK) {
|
||||
SaveState state;
|
||||
p_->cpu.setStatePtrs(state);
|
||||
p_->loadflags = flags;
|
||||
setInitState(state, p_->cpu.isCgb(), flags & GBA_CGB);
|
||||
p_->cpu.loadState(state);
|
||||
//p_->cpu.loadSavedata();
|
||||
|
||||
p_->stateNo = 1;
|
||||
p_->cpu.setOsdElement(std::auto_ptr<OsdElement>());
|
||||
}
|
||||
|
||||
return loadres;
|
||||
}
|
||||
|
||||
bool GB::isCgb() const {
|
||||
return p_->cpu.isCgb();
|
||||
}
|
||||
|
||||
bool GB::isLoaded() const {
|
||||
//return p_->cpu.loaded();
|
||||
return true;
|
||||
}
|
||||
|
||||
//void GB::saveSavedata() {
|
||||
// if (p_->cpu.loaded())
|
||||
// p_->cpu.saveSavedata();
|
||||
//}
|
||||
|
||||
void *GB::savedata_ptr() { return p_->cpu.savedata_ptr(); }
|
||||
unsigned GB::savedata_size() { return p_->cpu.savedata_size(); }
|
||||
void *GB::rtcdata_ptr() { return p_->cpu.rtcdata_ptr(); }
|
||||
unsigned GB::rtcdata_size() { return p_->cpu.rtcdata_size(); }
|
||||
|
||||
void GB::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) {
|
||||
p_->cpu.setDmgPaletteColor(palNum, colorNum, rgb32);
|
||||
}
|
||||
|
||||
void GB::loadState(const void *data) {
|
||||
SaveState state;
|
||||
p_->cpu.setStatePtrs(state);
|
||||
|
||||
if (StateSaver::loadState(state, data)) {
|
||||
p_->cpu.loadState(state);
|
||||
}
|
||||
}
|
||||
|
||||
//bool GB::saveState(const gambatte::uint_least32_t *const videoBuf, const int pitch) {
|
||||
// if (saveState(videoBuf, pitch, statePath(p_->cpu.saveBasePath(), p_->stateNo))) {
|
||||
// p_->cpu.setOsdElement(newStateSavedOsdElement(p_->stateNo));
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
//}
|
||||
|
||||
//bool GB::loadState() {
|
||||
// if (loadState(statePath(p_->cpu.saveBasePath(), p_->stateNo))) {
|
||||
// p_->cpu.setOsdElement(newStateLoadedOsdElement(p_->stateNo));
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
//}
|
||||
|
||||
void GB::saveState(void *data) {
|
||||
SaveState state;
|
||||
p_->cpu.setStatePtrs(state);
|
||||
p_->cpu.saveState(state);
|
||||
StateSaver::saveState(state, data);
|
||||
}
|
||||
|
||||
size_t GB::stateSize() const {
|
||||
SaveState state;
|
||||
p_->cpu.setStatePtrs(state);
|
||||
p_->cpu.saveState(state);
|
||||
return StateSaver::stateSize(state);
|
||||
|
||||
}
|
||||
|
||||
//void GB::selectState(int n) {
|
||||
// n -= (n / 10) * 10;
|
||||
// p_->stateNo = n < 0 ? n + 10 : n;
|
||||
//
|
||||
// if (p_->cpu.loaded())
|
||||
// p_->cpu.setOsdElement(newSaveStateOsdElement(statePath(p_->cpu.saveBasePath(), p_->stateNo), p_->stateNo));
|
||||
//}
|
||||
|
||||
//int GB::currentState() const { return p_->stateNo; }
|
||||
//
|
||||
std::string const GB::romTitle() const {
|
||||
//if (p_->cpu.loaded()) {
|
||||
char title[0x11];
|
||||
std::memcpy(title, p_->cpu.romTitle(), 0x10);
|
||||
title[(title[0xF] & 0x80) ? 0xF : 0x10] = '\0';
|
||||
return std::string(title);
|
||||
//}
|
||||
|
||||
//return std::string();
|
||||
}
|
||||
|
||||
PakInfo const GB::pakInfo() const { return p_->cpu.pakInfo(p_->loadflags & MULTICART_COMPAT); }
|
||||
|
||||
void GB::setGameGenie(const std::string &codes) {
|
||||
p_->cpu.setGameGenie(codes);
|
||||
}
|
||||
|
||||
void GB::setGameShark(const std::string &codes) {
|
||||
p_->cpu.setGameShark(codes);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aam�s *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef INITSTATE_H
|
||||
#define INITSTATE_H
|
||||
|
||||
namespace gambatte {
|
||||
void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,51 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef INSERTION_SORT_H
|
||||
#define INSERTION_SORT_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
template<typename T, class Less>
|
||||
void insertionSort(T *const start, T *const end, Less less) {
|
||||
if (start >= end)
|
||||
return;
|
||||
|
||||
T *a = start;
|
||||
|
||||
while (++a < end) {
|
||||
const T e = *a;
|
||||
|
||||
T *b = a;
|
||||
|
||||
while (b != start && less(e, *(b - 1))) {
|
||||
*b = *(b - 1);
|
||||
b = b - 1;
|
||||
}
|
||||
|
||||
*b = e;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void insertionSort(T *const start, T *const end) {
|
||||
insertionSort(start, end, std::less<T>());
|
||||
}
|
||||
|
||||
#endif /*INSERTION_SORT_H*/
|
||||
@@ -1,71 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "interrupter.h"
|
||||
#include "memory.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
Interrupter::Interrupter(unsigned short &SP_in, unsigned short &PC_in) :
|
||||
SP(SP_in),
|
||||
PC(PC_in)
|
||||
{}
|
||||
|
||||
unsigned long Interrupter::interrupt(const unsigned address, unsigned long cycleCounter, Memory &memory) {
|
||||
cycleCounter += 8;
|
||||
SP = (SP - 1) & 0xFFFF;
|
||||
memory.write(SP, PC >> 8, cycleCounter);
|
||||
cycleCounter += 4;
|
||||
SP = (SP - 1) & 0xFFFF;
|
||||
memory.write(SP, PC & 0xFF, cycleCounter);
|
||||
PC = address;
|
||||
cycleCounter += 8;
|
||||
|
||||
if (address == 0x40 && !gsCodes.empty())
|
||||
applyVblankCheats(cycleCounter, memory);
|
||||
|
||||
return cycleCounter;
|
||||
}
|
||||
|
||||
static int asHex(const char c) {
|
||||
return c >= 'A' ? c - 'A' + 0xA : c - '0';
|
||||
}
|
||||
|
||||
void Interrupter::setGameShark(const std::string &codes) {
|
||||
std::string code;
|
||||
gsCodes.clear();
|
||||
|
||||
for (std::size_t pos = 0; pos < codes.length() && (code = codes.substr(pos, codes.find('+', pos) - pos), true); pos += code.length() + 1) {
|
||||
if (code.length() >= 8) {
|
||||
GsCode gs;
|
||||
gs.type = asHex(code[0]) << 4 | asHex(code[1]);
|
||||
gs.value = (asHex(code[2]) << 4 | asHex(code[3])) & 0xFF;
|
||||
gs.address = (asHex(code[4]) << 4 | asHex(code[5]) | asHex(code[6]) << 12 | asHex(code[7]) << 8) & 0xFFFF;
|
||||
gsCodes.push_back(gs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Interrupter::applyVblankCheats(const unsigned long cycleCounter, Memory &memory) {
|
||||
for (std::size_t i = 0, size = gsCodes.size(); i < size; ++i) {
|
||||
if (gsCodes[i].type == 0x01)
|
||||
memory.write(gsCodes[i].address, gsCodes[i].value, cycleCounter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef INTERRUPTER_H
|
||||
#define INTERRUPTER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct GsCode {
|
||||
unsigned short address;
|
||||
unsigned char value;
|
||||
unsigned char type;
|
||||
};
|
||||
|
||||
class Interrupter {
|
||||
unsigned short &SP;
|
||||
unsigned short &PC;
|
||||
std::vector<GsCode> gsCodes;
|
||||
|
||||
void applyVblankCheats(unsigned long cc, class Memory &mem);
|
||||
public:
|
||||
Interrupter(unsigned short &SP, unsigned short &PC);
|
||||
unsigned long interrupt(const unsigned address, unsigned long cycleCounter, class Memory &memory);
|
||||
void setGameShark(const std::string &codes);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,103 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "interruptrequester.h"
|
||||
#include "savestate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
InterruptRequester::InterruptRequester() : minIntTime(0), ifreg_(0), iereg_(0) {}
|
||||
|
||||
void InterruptRequester::saveState(SaveState &state) const {
|
||||
state.mem.minIntTime = minIntTime;
|
||||
state.mem.IME = ime();
|
||||
state.mem.halted = halted();
|
||||
}
|
||||
|
||||
void InterruptRequester::loadState(const SaveState &state) {
|
||||
minIntTime = state.mem.minIntTime;
|
||||
ifreg_ = state.mem.ioamhram.get()[0x10F];
|
||||
iereg_ = state.mem.ioamhram.get()[0x1FF] & 0x1F;
|
||||
intFlags.set(state.mem.IME, state.mem.halted);
|
||||
|
||||
eventTimes.setValue<INTERRUPTS>(intFlags.imeOrHalted() && pendingIrqs() ? minIntTime : static_cast<unsigned long>(DISABLED_TIME));
|
||||
}
|
||||
|
||||
void InterruptRequester::resetCc(const unsigned long oldCc, const unsigned long newCc) {
|
||||
minIntTime = minIntTime < oldCc ? 0 : minIntTime - (oldCc - newCc);
|
||||
|
||||
if (eventTimes.value(INTERRUPTS) != DISABLED_TIME)
|
||||
eventTimes.setValue<INTERRUPTS>(minIntTime);
|
||||
}
|
||||
|
||||
void InterruptRequester::ei(const unsigned long cc) {
|
||||
intFlags.setIme();
|
||||
minIntTime = cc + 1;
|
||||
|
||||
if (pendingIrqs())
|
||||
eventTimes.setValue<INTERRUPTS>(minIntTime);
|
||||
}
|
||||
|
||||
void InterruptRequester::di() {
|
||||
intFlags.unsetIme();
|
||||
|
||||
if (!intFlags.imeOrHalted())
|
||||
eventTimes.setValue<INTERRUPTS>(DISABLED_TIME);
|
||||
}
|
||||
|
||||
void InterruptRequester::halt() {
|
||||
intFlags.setHalted();
|
||||
|
||||
if (pendingIrqs())
|
||||
eventTimes.setValue<INTERRUPTS>(minIntTime);
|
||||
}
|
||||
|
||||
void InterruptRequester::unhalt() {
|
||||
intFlags.unsetHalted();
|
||||
|
||||
if (!intFlags.imeOrHalted())
|
||||
eventTimes.setValue<INTERRUPTS>(DISABLED_TIME);
|
||||
}
|
||||
|
||||
void InterruptRequester::flagIrq(const unsigned bit) {
|
||||
ifreg_ |= bit;
|
||||
|
||||
if (intFlags.imeOrHalted() && pendingIrqs())
|
||||
eventTimes.setValue<INTERRUPTS>(minIntTime);
|
||||
}
|
||||
|
||||
void InterruptRequester::ackIrq(const unsigned bit) {
|
||||
ifreg_ ^= bit;
|
||||
di();
|
||||
}
|
||||
|
||||
void InterruptRequester::setIereg(const unsigned iereg) {
|
||||
iereg_ = iereg & 0x1F;
|
||||
|
||||
if (intFlags.imeOrHalted())
|
||||
eventTimes.setValue<INTERRUPTS>(pendingIrqs() ? minIntTime : static_cast<unsigned long>(DISABLED_TIME));
|
||||
}
|
||||
|
||||
void InterruptRequester::setIfreg(const unsigned ifreg) {
|
||||
ifreg_ = ifreg;
|
||||
|
||||
if (intFlags.imeOrHalted())
|
||||
eventTimes.setValue<INTERRUPTS>(pendingIrqs() ? minIntTime : static_cast<unsigned long>(DISABLED_TIME));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef INTERRUPT_REQUESTER_H
|
||||
#define INTERRUPT_REQUESTER_H
|
||||
|
||||
#include "counterdef.h"
|
||||
#include "minkeeper.h"
|
||||
|
||||
namespace gambatte {
|
||||
struct SaveState;
|
||||
enum MemEventId { UNHALT, END, BLIT, SERIAL, OAM, DMA, TIMA, VIDEO, INTERRUPTS };
|
||||
|
||||
class InterruptRequester {
|
||||
MinKeeper<INTERRUPTS + 1> eventTimes;
|
||||
unsigned long minIntTime;
|
||||
unsigned ifreg_;
|
||||
unsigned iereg_;
|
||||
|
||||
class IntFlags {
|
||||
unsigned char flags_;
|
||||
enum { IME_MASK = 1, HALTED_MASK = 2 };
|
||||
|
||||
public:
|
||||
IntFlags() : flags_(0) {}
|
||||
|
||||
bool ime() const { return flags_ & IME_MASK; }
|
||||
bool halted() const { return flags_ & HALTED_MASK; }
|
||||
bool imeOrHalted() const { return flags_; }
|
||||
|
||||
void setIme() { flags_ |= IME_MASK; }
|
||||
void unsetIme() { flags_ &= ~IME_MASK; }
|
||||
|
||||
void setHalted() { flags_ |= HALTED_MASK; }
|
||||
void unsetHalted() { flags_ &= ~HALTED_MASK; }
|
||||
|
||||
void set(const bool ime, const bool halted) { flags_ = halted * HALTED_MASK + ime * IME_MASK; }
|
||||
} intFlags;
|
||||
|
||||
public:
|
||||
InterruptRequester();
|
||||
|
||||
void saveState(SaveState &) const;
|
||||
void loadState(const SaveState &);
|
||||
|
||||
void resetCc(unsigned long oldCc, unsigned long newCc);
|
||||
|
||||
unsigned ifreg() const { return ifreg_; }
|
||||
unsigned pendingIrqs() const { return ifreg_ & iereg_; }
|
||||
bool ime() const { return intFlags.ime(); }
|
||||
bool halted() const { return intFlags.halted(); }
|
||||
|
||||
void ei(unsigned long cc);
|
||||
void di();
|
||||
void halt();
|
||||
void unhalt();
|
||||
void flagIrq(unsigned bit);
|
||||
void ackIrq(unsigned bit);
|
||||
void setIereg(unsigned iereg);
|
||||
void setIfreg(unsigned ifreg);
|
||||
|
||||
MemEventId minEventId() const { return static_cast<MemEventId>(eventTimes.min()); }
|
||||
unsigned long minEventTime() const { return eventTimes.minValue(); }
|
||||
template<MemEventId id> void setEventTime(unsigned long value) { eventTimes.setValue<id>(value); }
|
||||
void setEventTime(const MemEventId id, unsigned long value) { eventTimes.setValue(id, value); }
|
||||
unsigned long eventTime(MemEventId id) const { return eventTimes.value(id); }
|
||||
};
|
||||
|
||||
inline void flagHdmaReq(InterruptRequester *const intreq) { intreq->setEventTime<DMA>(0); }
|
||||
inline void flagGdmaReq(InterruptRequester *const intreq) { intreq->setEventTime<DMA>(1); }
|
||||
inline void ackDmaReq(InterruptRequester *const intreq) { intreq->setEventTime<DMA>(DISABLED_TIME); }
|
||||
inline bool hdmaReqFlagged(const InterruptRequester &intreq) { return intreq.eventTime(DMA) == 0; }
|
||||
inline bool gdmaReqFlagged(const InterruptRequester &intreq) { return intreq.eventTime(DMA) == 1; }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,730 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007-2010 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "cartridge.h"
|
||||
#include "file/file.h"
|
||||
#include "../savestate.h"
|
||||
#include "pakinfo_internal.h"
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
namespace {
|
||||
|
||||
static unsigned toMulti64Rombank(const unsigned rombank) {
|
||||
return (rombank >> 1 & 0x30) | (rombank & 0xF);
|
||||
}
|
||||
|
||||
class DefaultMbc : public Mbc {
|
||||
public:
|
||||
virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const {
|
||||
return (addr< 0x4000) == (bank == 0);
|
||||
}
|
||||
};
|
||||
|
||||
class Mbc0 : public DefaultMbc {
|
||||
MemPtrs &memptrs;
|
||||
bool enableRam;
|
||||
|
||||
public:
|
||||
explicit Mbc0(MemPtrs &memptrs)
|
||||
: memptrs(memptrs),
|
||||
enableRam(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void romWrite(const unsigned P, const unsigned data) {
|
||||
if (P < 0x2000) {
|
||||
enableRam = (data & 0xF) == 0xA;
|
||||
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void saveState(SaveState::Mem &ss) const {
|
||||
ss.enableRam = enableRam;
|
||||
}
|
||||
|
||||
virtual void loadState(const SaveState::Mem &ss) {
|
||||
enableRam = ss.enableRam;
|
||||
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
static inline unsigned rambanks(const MemPtrs &memptrs) {
|
||||
return static_cast<std::size_t>(memptrs.rambankdataend() - memptrs.rambankdata()) / 0x2000;
|
||||
}
|
||||
|
||||
static inline unsigned rombanks(const MemPtrs &memptrs) {
|
||||
return static_cast<std::size_t>(memptrs.romdataend() - memptrs.romdata() ) / 0x4000;
|
||||
}
|
||||
|
||||
class Mbc1 : public DefaultMbc {
|
||||
MemPtrs &memptrs;
|
||||
unsigned char rombank;
|
||||
unsigned char rambank;
|
||||
bool enableRam;
|
||||
bool rambankMode;
|
||||
|
||||
static unsigned adjustedRombank(unsigned bank) { return bank & 0x1F ? bank : bank | 1; }
|
||||
void setRambank() const { memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, rambank & (rambanks(memptrs) - 1)); }
|
||||
void setRombank() const { memptrs.setRombank(adjustedRombank(rombank & (rombanks(memptrs) - 1))); }
|
||||
|
||||
public:
|
||||
explicit Mbc1(MemPtrs &memptrs)
|
||||
: memptrs(memptrs),
|
||||
rombank(1),
|
||||
rambank(0),
|
||||
enableRam(false),
|
||||
rambankMode(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void romWrite(const unsigned P, const unsigned data) {
|
||||
switch (P >> 13 & 3) {
|
||||
case 0:
|
||||
enableRam = (data & 0xF) == 0xA;
|
||||
setRambank();
|
||||
break;
|
||||
case 1:
|
||||
rombank = rambankMode ? data & 0x1F : (rombank & 0x60) | (data & 0x1F);
|
||||
setRombank();
|
||||
break;
|
||||
case 2:
|
||||
if (rambankMode) {
|
||||
rambank = data & 3;
|
||||
setRambank();
|
||||
} else {
|
||||
rombank = (data << 5 & 0x60) | (rombank & 0x1F);
|
||||
setRombank();
|
||||
}
|
||||
|
||||
break;
|
||||
case 3:
|
||||
// Pretty sure this should take effect immediately, but I have a policy not to change old behavior
|
||||
// unless I have something (eg. a verified test or a game) that justifies it.
|
||||
rambankMode = data & 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void saveState(SaveState::Mem &ss) const {
|
||||
ss.rombank = rombank;
|
||||
ss.rambank = rambank;
|
||||
ss.enableRam = enableRam;
|
||||
ss.rambankMode = rambankMode;
|
||||
}
|
||||
|
||||
virtual void loadState(const SaveState::Mem &ss) {
|
||||
rombank = ss.rombank;
|
||||
rambank = ss.rambank;
|
||||
enableRam = ss.enableRam;
|
||||
rambankMode = ss.rambankMode;
|
||||
setRambank();
|
||||
setRombank();
|
||||
}
|
||||
};
|
||||
|
||||
class Mbc1Multi64 : public Mbc {
|
||||
MemPtrs &memptrs;
|
||||
unsigned char rombank;
|
||||
bool enableRam;
|
||||
bool rombank0Mode;
|
||||
|
||||
static unsigned adjustedRombank(unsigned bank) { return bank & 0x1F ? bank : bank | 1; }
|
||||
|
||||
void setRombank() const {
|
||||
if (rombank0Mode) {
|
||||
const unsigned rb = toMulti64Rombank(rombank);
|
||||
memptrs.setRombank0(rb & 0x30);
|
||||
memptrs.setRombank(adjustedRombank(rb));
|
||||
} else {
|
||||
memptrs.setRombank0(0);
|
||||
memptrs.setRombank(adjustedRombank(rombank & (rombanks(memptrs) - 1)));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
explicit Mbc1Multi64(MemPtrs &memptrs)
|
||||
: memptrs(memptrs),
|
||||
rombank(1),
|
||||
enableRam(false),
|
||||
rombank0Mode(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void romWrite(const unsigned P, const unsigned data) {
|
||||
switch (P >> 13 & 3) {
|
||||
case 0:
|
||||
enableRam = (data & 0xF) == 0xA;
|
||||
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
|
||||
break;
|
||||
case 1:
|
||||
rombank = (rombank & 0x60) | (data & 0x1F);
|
||||
memptrs.setRombank(adjustedRombank(rombank0Mode ? toMulti64Rombank(rombank) : rombank & (rombanks(memptrs) - 1)));
|
||||
break;
|
||||
case 2:
|
||||
rombank = (data << 5 & 0x60) | (rombank & 0x1F);
|
||||
setRombank();
|
||||
break;
|
||||
case 3:
|
||||
rombank0Mode = data & 1;
|
||||
setRombank();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void saveState(SaveState::Mem &ss) const {
|
||||
ss.rombank = rombank;
|
||||
ss.enableRam = enableRam;
|
||||
ss.rambankMode = rombank0Mode;
|
||||
}
|
||||
|
||||
virtual void loadState(const SaveState::Mem &ss) {
|
||||
rombank = ss.rombank;
|
||||
enableRam = ss.enableRam;
|
||||
rombank0Mode = ss.rambankMode;
|
||||
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
|
||||
setRombank();
|
||||
}
|
||||
|
||||
virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const {
|
||||
return (addr < 0x4000) == ((bank & 0xF) == 0);
|
||||
}
|
||||
};
|
||||
|
||||
class Mbc2 : public DefaultMbc {
|
||||
MemPtrs &memptrs;
|
||||
unsigned char rombank;
|
||||
bool enableRam;
|
||||
|
||||
public:
|
||||
explicit Mbc2(MemPtrs &memptrs)
|
||||
: memptrs(memptrs),
|
||||
rombank(1),
|
||||
enableRam(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void romWrite(const unsigned P, const unsigned data) {
|
||||
switch (P & 0x6100) {
|
||||
case 0x0000:
|
||||
enableRam = (data & 0xF) == 0xA;
|
||||
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
|
||||
break;
|
||||
case 0x2100:
|
||||
rombank = data & 0xF;
|
||||
memptrs.setRombank(rombank & (rombanks(memptrs) - 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void saveState(SaveState::Mem &ss) const {
|
||||
ss.rombank = rombank;
|
||||
ss.enableRam = enableRam;
|
||||
}
|
||||
|
||||
virtual void loadState(const SaveState::Mem &ss) {
|
||||
rombank = ss.rombank;
|
||||
enableRam = ss.enableRam;
|
||||
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
|
||||
memptrs.setRombank(rombank & (rombanks(memptrs) - 1));
|
||||
}
|
||||
};
|
||||
|
||||
class Mbc3 : public DefaultMbc {
|
||||
MemPtrs &memptrs;
|
||||
Rtc *const rtc;
|
||||
unsigned char rombank;
|
||||
unsigned char rambank;
|
||||
bool enableRam;
|
||||
|
||||
void setRambank() const {
|
||||
unsigned flags = enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0;
|
||||
|
||||
if (rtc) {
|
||||
rtc->set(enableRam, rambank);
|
||||
|
||||
if (rtc->getActive())
|
||||
flags |= MemPtrs::RTC_EN;
|
||||
}
|
||||
|
||||
memptrs.setRambank(flags, rambank & (rambanks(memptrs) - 1));
|
||||
}
|
||||
|
||||
public:
|
||||
Mbc3(MemPtrs &memptrs, Rtc *const rtc)
|
||||
: memptrs(memptrs),
|
||||
rtc(rtc),
|
||||
rombank(1),
|
||||
rambank(0),
|
||||
enableRam(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void romWrite(const unsigned P, const unsigned data) {
|
||||
switch (P >> 13 & 3) {
|
||||
case 0:
|
||||
enableRam = (data & 0xF) == 0xA;
|
||||
setRambank();
|
||||
break;
|
||||
case 1:
|
||||
rombank = data & 0x7F;
|
||||
memptrs.setRombank(rombank & (rombanks(memptrs) - 1));
|
||||
break;
|
||||
case 2:
|
||||
rambank = data;
|
||||
setRambank();
|
||||
break;
|
||||
case 3:
|
||||
if (rtc)
|
||||
rtc->latch(data);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void saveState(SaveState::Mem &ss) const {
|
||||
ss.rombank = rombank;
|
||||
ss.rambank = rambank;
|
||||
ss.enableRam = enableRam;
|
||||
}
|
||||
|
||||
virtual void loadState(const SaveState::Mem &ss) {
|
||||
rombank = ss.rombank;
|
||||
rambank = ss.rambank;
|
||||
enableRam = ss.enableRam;
|
||||
setRambank();
|
||||
memptrs.setRombank(rombank & (rombanks(memptrs) - 1));
|
||||
}
|
||||
};
|
||||
|
||||
class HuC1 : public DefaultMbc {
|
||||
MemPtrs &memptrs;
|
||||
unsigned char rombank;
|
||||
unsigned char rambank;
|
||||
bool enableRam;
|
||||
bool rambankMode;
|
||||
|
||||
void setRambank() const {
|
||||
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : MemPtrs::READ_EN,
|
||||
rambankMode ? rambank & (rambanks(memptrs) - 1) : 0);
|
||||
}
|
||||
|
||||
void setRombank() const { memptrs.setRombank((rambankMode ? rombank : rambank << 6 | rombank) & (rombanks(memptrs) - 1)); }
|
||||
|
||||
public:
|
||||
explicit HuC1(MemPtrs &memptrs)
|
||||
: memptrs(memptrs),
|
||||
rombank(1),
|
||||
rambank(0),
|
||||
enableRam(false),
|
||||
rambankMode(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void romWrite(const unsigned P, const unsigned data) {
|
||||
switch (P >> 13 & 3) {
|
||||
case 0:
|
||||
enableRam = (data & 0xF) == 0xA;
|
||||
setRambank();
|
||||
break;
|
||||
case 1:
|
||||
rombank = data & 0x3F;
|
||||
setRombank();
|
||||
break;
|
||||
case 2:
|
||||
rambank = data & 3;
|
||||
rambankMode ? setRambank() : setRombank();
|
||||
break;
|
||||
case 3:
|
||||
rambankMode = data & 1;
|
||||
setRambank();
|
||||
setRombank();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void saveState(SaveState::Mem &ss) const {
|
||||
ss.rombank = rombank;
|
||||
ss.rambank = rambank;
|
||||
ss.enableRam = enableRam;
|
||||
ss.rambankMode = rambankMode;
|
||||
}
|
||||
|
||||
virtual void loadState(const SaveState::Mem &ss) {
|
||||
rombank = ss.rombank;
|
||||
rambank = ss.rambank;
|
||||
enableRam = ss.enableRam;
|
||||
rambankMode = ss.rambankMode;
|
||||
setRambank();
|
||||
setRombank();
|
||||
}
|
||||
};
|
||||
|
||||
class Mbc5 : public DefaultMbc {
|
||||
MemPtrs &memptrs;
|
||||
unsigned short rombank;
|
||||
unsigned char rambank;
|
||||
bool enableRam;
|
||||
|
||||
static unsigned adjustedRombank(const unsigned bank) { return bank ? bank : 1; }
|
||||
void setRambank() const { memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, rambank & (rambanks(memptrs) - 1)); }
|
||||
void setRombank() const { memptrs.setRombank(adjustedRombank(rombank & (rombanks(memptrs) - 1))); }
|
||||
|
||||
public:
|
||||
explicit Mbc5(MemPtrs &memptrs)
|
||||
: memptrs(memptrs),
|
||||
rombank(1),
|
||||
rambank(0),
|
||||
enableRam(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void romWrite(const unsigned P, const unsigned data) {
|
||||
switch (P >> 13 & 3) {
|
||||
case 0:
|
||||
enableRam = (data & 0xF) == 0xA;
|
||||
setRambank();
|
||||
break;
|
||||
case 1:
|
||||
rombank = P < 0x3000 ? (rombank & 0x100) | data
|
||||
: (data << 8 & 0x100) | (rombank & 0xFF);
|
||||
setRombank();
|
||||
break;
|
||||
case 2:
|
||||
rambank = data & 0xF;
|
||||
setRambank();
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void saveState(SaveState::Mem &ss) const {
|
||||
ss.rombank = rombank;
|
||||
ss.rambank = rambank;
|
||||
ss.enableRam = enableRam;
|
||||
}
|
||||
|
||||
virtual void loadState(const SaveState::Mem &ss) {
|
||||
rombank = ss.rombank;
|
||||
rambank = ss.rambank;
|
||||
enableRam = ss.enableRam;
|
||||
setRambank();
|
||||
setRombank();
|
||||
}
|
||||
};
|
||||
|
||||
//static bool hasRtc(const unsigned headerByte0x147) {
|
||||
// switch (headerByte0x147) {
|
||||
// case 0x0F:
|
||||
// case 0x10: return true;
|
||||
// default: return false;
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
void Cartridge::setStatePtrs(SaveState &state) {
|
||||
state.mem.vram.set(memptrs.vramdata(), memptrs.vramdataend() - memptrs.vramdata());
|
||||
state.mem.sram.set(memptrs.rambankdata(), memptrs.rambankdataend() - memptrs.rambankdata());
|
||||
state.mem.wram.set(memptrs.wramdata(0), memptrs.wramdataend() - memptrs.wramdata(0));
|
||||
}
|
||||
|
||||
void Cartridge::saveState(SaveState &state) const {
|
||||
mbc->saveState(state.mem);
|
||||
rtc.saveState(state);
|
||||
}
|
||||
|
||||
void Cartridge::loadState(const SaveState &state) {
|
||||
rtc.loadState(state);
|
||||
mbc->loadState(state.mem);
|
||||
}
|
||||
|
||||
//static const std::string stripExtension(const std::string &str) {
|
||||
// const std::string::size_type lastDot = str.find_last_of('.');
|
||||
// const std::string::size_type lastSlash = str.find_last_of('/');
|
||||
//
|
||||
// if (lastDot != std::string::npos && (lastSlash == std::string::npos || lastSlash < lastDot))
|
||||
// return str.substr(0, lastDot);
|
||||
//
|
||||
// return str;
|
||||
//}
|
||||
//
|
||||
//static const std::string stripDir(const std::string &str) {
|
||||
// const std::string::size_type lastSlash = str.find_last_of('/');
|
||||
//
|
||||
// if (lastSlash != std::string::npos)
|
||||
// return str.substr(lastSlash + 1);
|
||||
//
|
||||
// return str;
|
||||
//}
|
||||
//
|
||||
//const std::string Cartridge::saveBasePath() const {
|
||||
// return saveDir.empty() ? defaultSaveBasePath : saveDir + stripDir(defaultSaveBasePath);
|
||||
//}
|
||||
//
|
||||
//void Cartridge::setSaveDir(const std::string &dir) {
|
||||
// saveDir = dir;
|
||||
//
|
||||
// if (!saveDir.empty() && saveDir[saveDir.length() - 1] != '/')
|
||||
// saveDir += '/';
|
||||
//}
|
||||
//
|
||||
//static void enforce8bit(unsigned char *data, unsigned long sz) {
|
||||
// if (static_cast<unsigned char>(0x100))
|
||||
// while (sz--)
|
||||
// *data++ &= 0xFF;
|
||||
//}
|
||||
|
||||
static unsigned pow2ceil(unsigned n) {
|
||||
--n;
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
++n;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static bool presumedMulti64Mbc1(unsigned char const header[], unsigned const rombanks) {
|
||||
return header[0x147] == 1 && header[0x149] == 0 && rombanks == 64;
|
||||
}
|
||||
|
||||
LoadRes Cartridge::loadROM(std::string const &romfile, bool const forceDmg, bool const multicartCompat) {
|
||||
const std::auto_ptr<File> rom(newFileInstance(romfile));
|
||||
|
||||
if (rom->fail())
|
||||
return LOADRES_IO_ERROR;
|
||||
|
||||
unsigned rambanks = 1;
|
||||
unsigned rombanks = 2;
|
||||
bool cgb = false;
|
||||
enum Cartridgetype { PLAIN, MBC1, MBC2, MBC3, MBC5, HUC1 } type = PLAIN;
|
||||
|
||||
{
|
||||
unsigned char header[0x150];
|
||||
rom->read(reinterpret_cast<char*>(header), sizeof header);
|
||||
|
||||
switch (header[0x0147]) {
|
||||
case 0x00: type = PLAIN; break;
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x03: type = MBC1; break;
|
||||
case 0x05:
|
||||
case 0x06: type = MBC2; break;
|
||||
case 0x08:
|
||||
case 0x09: type = PLAIN; break;
|
||||
case 0x0B:
|
||||
case 0x0C:
|
||||
case 0x0D: return LOADRES_UNSUPPORTED_MBC_MMM01;
|
||||
case 0x0F:
|
||||
case 0x10:
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
case 0x13: type = MBC3; break;
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
case 0x17: return LOADRES_UNSUPPORTED_MBC_MBC4;
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
case 0x1C:
|
||||
case 0x1D:
|
||||
case 0x1E: type = MBC5; break;
|
||||
case 0xFC: return LOADRES_UNSUPPORTED_MBC_POCKET_CAMERA;
|
||||
case 0xFD: return LOADRES_UNSUPPORTED_MBC_TAMA5;
|
||||
case 0xFE: return LOADRES_UNSUPPORTED_MBC_HUC3;
|
||||
case 0xFF: type = HUC1; break;
|
||||
default: return LOADRES_BAD_FILE_OR_UNKNOWN_MBC;
|
||||
}
|
||||
|
||||
/*switch (header[0x0148]) {
|
||||
case 0x00: rombanks = 2; break;
|
||||
case 0x01: rombanks = 4; break;
|
||||
case 0x02: rombanks = 8; break;
|
||||
case 0x03: rombanks = 16; break;
|
||||
case 0x04: rombanks = 32; break;
|
||||
case 0x05: rombanks = 64; break;
|
||||
case 0x06: rombanks = 128; break;
|
||||
case 0x07: rombanks = 256; break;
|
||||
case 0x08: rombanks = 512; break;
|
||||
case 0x52: rombanks = 72; break;
|
||||
case 0x53: rombanks = 80; break;
|
||||
case 0x54: rombanks = 96; break;
|
||||
default: return -1;
|
||||
}*/
|
||||
|
||||
rambanks = numRambanksFromH14x(header[0x147], header[0x149]);
|
||||
cgb = header[0x0143] >> 7 & (1 ^ forceDmg);
|
||||
}
|
||||
|
||||
std::size_t const filesize = rom->size();
|
||||
rombanks = std::max(pow2ceil(filesize / 0x4000), 2u);
|
||||
|
||||
//defaultSaveBasePath.clear();
|
||||
ggUndoList.clear();
|
||||
mbc.reset();
|
||||
memptrs.reset(rombanks, rambanks, cgb ? 8 : 2);
|
||||
rtc.set(false, 0);
|
||||
|
||||
rom->rewind();
|
||||
rom->read(reinterpret_cast<char*>(memptrs.romdata()), (filesize / 0x4000) * 0x4000ul);
|
||||
std::memset(memptrs.romdata() + (filesize / 0x4000) * 0x4000ul, 0xFF, (rombanks - filesize / 0x4000) * 0x4000ul);
|
||||
//enforce8bit(memptrs.romdata(), rombanks * 0x4000ul);
|
||||
|
||||
if (rom->fail())
|
||||
return LOADRES_IO_ERROR;
|
||||
|
||||
//defaultSaveBasePath = stripExtension(romfile);
|
||||
|
||||
switch (type) {
|
||||
case PLAIN: mbc.reset(new Mbc0(memptrs)); break;
|
||||
case MBC1:
|
||||
if (multicartCompat && presumedMulti64Mbc1(memptrs.romdata(), rombanks)) {
|
||||
mbc.reset(new Mbc1Multi64(memptrs));
|
||||
} else
|
||||
mbc.reset(new Mbc1(memptrs));
|
||||
|
||||
break;
|
||||
case MBC2: mbc.reset(new Mbc2(memptrs)); break;
|
||||
case MBC3: mbc.reset(new Mbc3(memptrs, hasRtc() ? &rtc : 0)); break;
|
||||
case MBC5: mbc.reset(new Mbc5(memptrs)); break;
|
||||
case HUC1: mbc.reset(new HuC1(memptrs)); break;
|
||||
}
|
||||
|
||||
return LOADRES_OK;
|
||||
}
|
||||
|
||||
//static bool hasBattery(const unsigned char headerByte0x147) {
|
||||
// switch (headerByte0x147) {
|
||||
// case 0x03:
|
||||
// case 0x06:
|
||||
// case 0x09:
|
||||
// case 0x0F:
|
||||
// case 0x10:
|
||||
// case 0x13:
|
||||
// case 0x1B:
|
||||
// case 0x1E:
|
||||
// case 0xFF: return true;
|
||||
// default: return false;
|
||||
// }
|
||||
//}
|
||||
|
||||
//void Cartridge::loadSavedata() {
|
||||
// const std::string &sbp = saveBasePath();
|
||||
//
|
||||
// if (hasBattery()) {
|
||||
// std::ifstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::in);
|
||||
//
|
||||
// if (file.is_open()) {
|
||||
// file.read(reinterpret_cast<char*>(memptrs.rambankdata()), memptrs.rambankdataend() - memptrs.rambankdata());
|
||||
// enforce8bit(memptrs.rambankdata(), memptrs.rambankdataend() - memptrs.rambankdata());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (hasRtc()) {
|
||||
// std::ifstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::in);
|
||||
//
|
||||
// if (file.is_open()) {
|
||||
// unsigned long basetime = file.get() & 0xFF;
|
||||
//
|
||||
// basetime = basetime << 8 | (file.get() & 0xFF);
|
||||
// basetime = basetime << 8 | (file.get() & 0xFF);
|
||||
// basetime = basetime << 8 | (file.get() & 0xFF);
|
||||
//
|
||||
// rtc.setBaseTime(basetime);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void Cartridge::saveSavedata() {
|
||||
// const std::string &sbp = saveBasePath();
|
||||
//
|
||||
// if (hasBattery()) {
|
||||
// std::ofstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::out);
|
||||
// file.write(reinterpret_cast<const char*>(memptrs.rambankdata()), memptrs.rambankdataend() - memptrs.rambankdata());
|
||||
// }
|
||||
//
|
||||
// if (hasRtc()) {
|
||||
// std::ofstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::out);
|
||||
// const unsigned long basetime = rtc.getBaseTime();
|
||||
//
|
||||
// file.put(basetime >> 24 & 0xFF);
|
||||
// file.put(basetime >> 16 & 0xFF);
|
||||
// file.put(basetime >> 8 & 0xFF);
|
||||
// file.put(basetime & 0xFF);
|
||||
// }
|
||||
//}
|
||||
|
||||
static int asHex(const char c) {
|
||||
return c >= 'A' ? c - 'A' + 0xA : c - '0';
|
||||
}
|
||||
|
||||
void Cartridge::applyGameGenie(const std::string &code) {
|
||||
if (6 < code.length()) {
|
||||
const unsigned val = (asHex(code[0]) << 4 | asHex(code[1])) & 0xFF;
|
||||
const unsigned addr = (asHex(code[2]) << 8 | asHex(code[4]) << 4 | asHex(code[5]) | (asHex(code[6]) ^ 0xF) << 12) & 0x7FFF;
|
||||
unsigned cmp = 0xFFFF;
|
||||
|
||||
if (10 < code.length()) {
|
||||
cmp = (asHex(code[8]) << 4 | asHex(code[10])) ^ 0xFF;
|
||||
cmp = ((cmp >> 2 | cmp << 6) ^ 0x45) & 0xFF;
|
||||
}
|
||||
|
||||
for (unsigned bank = 0; bank < static_cast<std::size_t>(memptrs.romdataend() - memptrs.romdata()) / 0x4000; ++bank) {
|
||||
if (mbc->isAddressWithinAreaRombankCanBeMappedTo(addr, bank)
|
||||
&& (cmp > 0xFF || memptrs.romdata()[bank * 0x4000ul + (addr & 0x3FFF)] == cmp)) {
|
||||
ggUndoList.push_back(AddrData(bank * 0x4000ul + (addr & 0x3FFF), memptrs.romdata()[bank * 0x4000ul + (addr & 0x3FFF)]));
|
||||
memptrs.romdata()[bank * 0x4000ul + (addr & 0x3FFF)] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::setGameGenie(const std::string &codes) {
|
||||
if (loaded()) {
|
||||
for (std::vector<AddrData>::reverse_iterator it = ggUndoList.rbegin(), end = ggUndoList.rend(); it != end; ++it) {
|
||||
if (memptrs.romdata() + it->addr < memptrs.romdataend())
|
||||
memptrs.romdata()[it->addr] = it->data;
|
||||
}
|
||||
|
||||
ggUndoList.clear();
|
||||
|
||||
std::string code;
|
||||
for (std::size_t pos = 0; pos < codes.length()
|
||||
&& (code = codes.substr(pos, codes.find('+', pos) - pos), true); pos += code.length() + 1) {
|
||||
applyGameGenie(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PakInfo const Cartridge::pakInfo(bool const multipakCompat) const {
|
||||
if (loaded()) {
|
||||
unsigned const rombs = rombanks(memptrs);
|
||||
return PakInfo(multipakCompat && presumedMulti64Mbc1(memptrs.romdata(), rombs),
|
||||
rombs,
|
||||
memptrs.romdata());
|
||||
}
|
||||
|
||||
return PakInfo();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007-2010 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef CARTRIDGE_H
|
||||
#define CARTRIDGE_H
|
||||
|
||||
#include "loadres.h"
|
||||
#include "memptrs.h"
|
||||
#include "rtc.h"
|
||||
#include "savestate.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class Mbc {
|
||||
public:
|
||||
virtual ~Mbc() {}
|
||||
virtual void romWrite(unsigned P, unsigned data) = 0;
|
||||
virtual void saveState(SaveState::Mem &ss) const = 0;
|
||||
virtual void loadState(const SaveState::Mem &ss) = 0;
|
||||
virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned address, unsigned rombank) const = 0;
|
||||
};
|
||||
|
||||
class Cartridge {
|
||||
struct AddrData {
|
||||
unsigned long addr;
|
||||
unsigned char data;
|
||||
AddrData(unsigned long addr, unsigned data) : addr(addr), data(data) {}
|
||||
};
|
||||
|
||||
MemPtrs memptrs;
|
||||
Rtc rtc;
|
||||
std::auto_ptr<Mbc> mbc;
|
||||
//std::string defaultSaveBasePath;
|
||||
//std::string saveDir;
|
||||
std::vector<AddrData> ggUndoList;
|
||||
|
||||
void applyGameGenie(const std::string &code);
|
||||
|
||||
bool hasBattery() const {
|
||||
switch (memptrs.romdata(0)[0x147]) {
|
||||
case 0x03:
|
||||
case 0x06:
|
||||
case 0x09:
|
||||
case 0x0F:
|
||||
case 0x10:
|
||||
case 0x13:
|
||||
case 0x1B:
|
||||
case 0x1E: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasRtc() const {
|
||||
switch (memptrs.romdata(0)[0x147]) {
|
||||
case 0x0F:
|
||||
case 0x10: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void setStatePtrs(SaveState &);
|
||||
void saveState(SaveState &) const;
|
||||
void loadState(const SaveState &);
|
||||
|
||||
bool loaded() const { return mbc.get(); }
|
||||
|
||||
const unsigned char * rmem(unsigned area) const { return memptrs.rmem(area); }
|
||||
unsigned char * wmem(unsigned area) const { return memptrs.wmem(area); }
|
||||
unsigned char * vramdata() const { return memptrs.vramdata(); }
|
||||
unsigned char * romdata(unsigned area) const { return memptrs.romdata(area); }
|
||||
unsigned char * wramdata(unsigned area) const { return memptrs.wramdata(area); }
|
||||
const unsigned char * rdisabledRam() const { return memptrs.rdisabledRam(); }
|
||||
const unsigned char * rsrambankptr() const { return memptrs.rsrambankptr(); }
|
||||
unsigned char * wsrambankptr() const { return memptrs.wsrambankptr(); }
|
||||
unsigned char * vrambankptr() const { return memptrs.vrambankptr(); }
|
||||
OamDmaSrc oamDmaSrc() const { return memptrs.oamDmaSrc(); }
|
||||
|
||||
void setVrambank(unsigned bank) { memptrs.setVrambank(bank); }
|
||||
void setWrambank(unsigned bank) { memptrs.setWrambank(bank); }
|
||||
void setOamDmaSrc(OamDmaSrc oamDmaSrc) { memptrs.setOamDmaSrc(oamDmaSrc); }
|
||||
|
||||
void mbcWrite(unsigned addr, unsigned data) { mbc->romWrite(addr, data); }
|
||||
|
||||
bool isCgb() const { return gambatte::isCgb(memptrs); }
|
||||
|
||||
void rtcWrite(unsigned data) { rtc.write(data); }
|
||||
unsigned char rtcRead() const { return *rtc.getActive(); }
|
||||
|
||||
//void loadSavedata();
|
||||
//void saveSavedata();
|
||||
const std::string saveBasePath() const;
|
||||
void setSaveDir(const std::string &dir);
|
||||
LoadRes loadROM(const std::string &romfile, bool forceDmg, bool multicartCompat);
|
||||
char const * romTitle() const { return reinterpret_cast<const char *>(memptrs.romdata() + 0x134); }
|
||||
class PakInfo const pakInfo(bool multicartCompat) const;
|
||||
void setGameGenie(const std::string &codes);
|
||||
|
||||
void *savedata_ptr()
|
||||
{
|
||||
// Check ROM header for battery.
|
||||
if (hasBattery())
|
||||
return memptrs.rambankdata();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned savedata_size()
|
||||
{
|
||||
if (hasBattery())
|
||||
return memptrs.rambankdataend() - memptrs.rambankdata();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Not endian-safe at all, but hey.
|
||||
void *rtcdata_ptr()
|
||||
{
|
||||
if (hasRtc())
|
||||
return &rtc.getBaseTime();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned rtcdata_size()
|
||||
{
|
||||
if (hasRtc())
|
||||
return sizeof(rtc.getBaseTime());
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,139 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007-2010 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "memptrs.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
MemPtrs::MemPtrs()
|
||||
: rmem_(), wmem_(), romdata_(), wramdata_(), vrambankptr_(0), rsrambankptr_(0),
|
||||
wsrambankptr_(0), memchunk_(0), rambankdata_(0), wramdataend_(0), oamDmaSrc_(OAM_DMA_SRC_OFF)
|
||||
{
|
||||
}
|
||||
|
||||
MemPtrs::~MemPtrs() {
|
||||
delete []memchunk_;
|
||||
}
|
||||
|
||||
void MemPtrs::reset(const unsigned rombanks, const unsigned rambanks, const unsigned wrambanks) {
|
||||
delete []memchunk_;
|
||||
memchunk_ = new unsigned char[0x4000 + rombanks * 0x4000ul + 0x4000 + rambanks * 0x2000ul + wrambanks * 0x1000ul + 0x4000];
|
||||
|
||||
romdata_[0] = romdata();
|
||||
rambankdata_ = romdata_[0] + rombanks * 0x4000ul + 0x4000;
|
||||
wramdata_[0] = rambankdata_ + rambanks * 0x2000ul;
|
||||
wramdataend_ = wramdata_[0] + wrambanks * 0x1000ul;
|
||||
|
||||
std::memset(rdisabledRamw(), 0xFF, 0x2000);
|
||||
|
||||
oamDmaSrc_ = OAM_DMA_SRC_OFF;
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
rmem_[0xC] = wmem_[0xC] = wramdata_[0] - 0xC000;
|
||||
rmem_[0xE] = wmem_[0xE] = wramdata_[0] - 0xE000;
|
||||
setRombank(1);
|
||||
setRambank(0, 0);
|
||||
setVrambank(0);
|
||||
setWrambank(1);
|
||||
}
|
||||
|
||||
void MemPtrs::setRombank0(const unsigned bank) {
|
||||
romdata_[0] = romdata() + bank * 0x4000ul;
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setRombank(const unsigned bank) {
|
||||
romdata_[1] = romdata() + bank * 0x4000ul - 0x4000;
|
||||
rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setRambank(const unsigned flags, const unsigned rambank) {
|
||||
unsigned char *const srambankptr = flags & RTC_EN
|
||||
? 0
|
||||
: (rambankdata() != rambankdataend()
|
||||
? rambankdata_ + rambank * 0x2000ul - 0xA000 : wdisabledRam() - 0xA000);
|
||||
|
||||
rsrambankptr_ = (flags & READ_EN) && srambankptr != wdisabledRam() - 0xA000 ? srambankptr : rdisabledRamw() - 0xA000;
|
||||
wsrambankptr_ = flags & WRITE_EN ? srambankptr : wdisabledRam() - 0xA000;
|
||||
rmem_[0xB] = rmem_[0xA] = rsrambankptr_;
|
||||
wmem_[0xB] = wmem_[0xA] = wsrambankptr_;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setWrambank(const unsigned bank) {
|
||||
wramdata_[1] = wramdata_[0] + ((bank & 0x07) ? (bank & 0x07) : 1) * 0x1000;
|
||||
rmem_[0xD] = wmem_[0xD] = wramdata_[1] - 0xD000;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setOamDmaSrc(const OamDmaSrc oamDmaSrc) {
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
|
||||
rmem_[0xB] = rmem_[0xA] = rsrambankptr_;
|
||||
wmem_[0xB] = wmem_[0xA] = wsrambankptr_;
|
||||
rmem_[0xC] = wmem_[0xC] = wramdata_[0] - 0xC000;
|
||||
rmem_[0xD] = wmem_[0xD] = wramdata_[1] - 0xD000;
|
||||
rmem_[0xE] = wmem_[0xE] = wramdata_[0] - 0xE000;
|
||||
|
||||
oamDmaSrc_ = oamDmaSrc;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::disconnectOamDmaAreas() {
|
||||
if (isCgb(*this)) {
|
||||
switch (oamDmaSrc_) {
|
||||
case OAM_DMA_SRC_ROM: // fall through
|
||||
case OAM_DMA_SRC_SRAM:
|
||||
case OAM_DMA_SRC_INVALID:
|
||||
std::fill(rmem_, rmem_ + 8, static_cast<unsigned char *>(0));
|
||||
rmem_[0xB] = rmem_[0xA] = 0;
|
||||
wmem_[0xB] = wmem_[0xA] = 0;
|
||||
break;
|
||||
case OAM_DMA_SRC_VRAM:
|
||||
break;
|
||||
case OAM_DMA_SRC_WRAM:
|
||||
rmem_[0xE] = rmem_[0xD] = rmem_[0xC] = 0;
|
||||
wmem_[0xE] = wmem_[0xD] = wmem_[0xC] = 0;
|
||||
break;
|
||||
case OAM_DMA_SRC_OFF:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (oamDmaSrc_) {
|
||||
case OAM_DMA_SRC_ROM: // fall through
|
||||
case OAM_DMA_SRC_SRAM:
|
||||
case OAM_DMA_SRC_WRAM:
|
||||
case OAM_DMA_SRC_INVALID:
|
||||
std::fill(rmem_, rmem_ + 8, static_cast<unsigned char *>(0));
|
||||
rmem_[0xB] = rmem_[0xA] = 0;
|
||||
wmem_[0xB] = wmem_[0xA] = 0;
|
||||
rmem_[0xE] = rmem_[0xD] = rmem_[0xC] = 0;
|
||||
wmem_[0xE] = wmem_[0xD] = wmem_[0xC] = 0;
|
||||
break;
|
||||
case OAM_DMA_SRC_VRAM:
|
||||
break;
|
||||
case OAM_DMA_SRC_OFF:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007-2010 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef MEMPTRS_H
|
||||
#define MEMPTRS_H
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
enum OamDmaSrc { OAM_DMA_SRC_ROM, OAM_DMA_SRC_SRAM, OAM_DMA_SRC_VRAM,
|
||||
OAM_DMA_SRC_WRAM, OAM_DMA_SRC_INVALID, OAM_DMA_SRC_OFF };
|
||||
|
||||
class MemPtrs {
|
||||
const unsigned char *rmem_[0x10];
|
||||
unsigned char *wmem_[0x10];
|
||||
|
||||
unsigned char *romdata_[2];
|
||||
unsigned char *wramdata_[2];
|
||||
unsigned char *vrambankptr_;
|
||||
unsigned char *rsrambankptr_;
|
||||
unsigned char *wsrambankptr_;
|
||||
unsigned char *memchunk_;
|
||||
unsigned char *rambankdata_;
|
||||
unsigned char *wramdataend_;
|
||||
|
||||
OamDmaSrc oamDmaSrc_;
|
||||
|
||||
MemPtrs(const MemPtrs &);
|
||||
MemPtrs & operator=(const MemPtrs &);
|
||||
void disconnectOamDmaAreas();
|
||||
unsigned char * rdisabledRamw() const { return wramdataend_ ; }
|
||||
unsigned char * wdisabledRam() const { return wramdataend_ + 0x2000; }
|
||||
public:
|
||||
enum RamFlag { READ_EN = 1, WRITE_EN = 2, RTC_EN = 4 };
|
||||
|
||||
MemPtrs();
|
||||
~MemPtrs();
|
||||
void reset(unsigned rombanks, unsigned rambanks, unsigned wrambanks);
|
||||
|
||||
const unsigned char * rmem(unsigned area) const { return rmem_[area]; }
|
||||
unsigned char * wmem(unsigned area) const { return wmem_[area]; }
|
||||
unsigned char * vramdata() const { return rambankdata_ - 0x4000; }
|
||||
unsigned char * vramdataend() const { return rambankdata_; }
|
||||
unsigned char * romdata() const { return memchunk_ + 0x4000; }
|
||||
unsigned char * romdata(unsigned area) const { return romdata_[area]; }
|
||||
unsigned char * romdataend() const { return rambankdata_ - 0x4000; }
|
||||
unsigned char * wramdata(unsigned area) const { return wramdata_[area]; }
|
||||
unsigned char * wramdataend() const { return wramdataend_; }
|
||||
unsigned char * rambankdata() const { return rambankdata_; }
|
||||
unsigned char * rambankdataend() const { return wramdata_[0]; }
|
||||
const unsigned char * rdisabledRam() const { return rdisabledRamw(); }
|
||||
const unsigned char * rsrambankptr() const { return rsrambankptr_; }
|
||||
unsigned char * wsrambankptr() const { return wsrambankptr_; }
|
||||
unsigned char * vrambankptr() const { return vrambankptr_; }
|
||||
OamDmaSrc oamDmaSrc() const { return oamDmaSrc_; }
|
||||
|
||||
void setRombank0(unsigned bank);
|
||||
void setRombank(unsigned bank);
|
||||
void setRambank(unsigned ramFlags, unsigned rambank);
|
||||
void setVrambank(unsigned bank) { vrambankptr_ = vramdata() + bank * 0x2000ul - 0x8000; }
|
||||
void setWrambank(unsigned bank);
|
||||
void setOamDmaSrc(OamDmaSrc oamDmaSrc);
|
||||
};
|
||||
|
||||
inline bool isCgb(const MemPtrs &memptrs) {
|
||||
return memptrs.wramdataend() - memptrs.wramdata(0) == 0x8000;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,156 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "rtc.h"
|
||||
#include "../savestate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
Rtc::Rtc()
|
||||
: activeData(NULL),
|
||||
activeSet(NULL),
|
||||
baseTime(0),
|
||||
haltTime(0),
|
||||
index(5),
|
||||
dataDh(0),
|
||||
dataDl(0),
|
||||
dataH(0),
|
||||
dataM(0),
|
||||
dataS(0),
|
||||
enabled(false),
|
||||
lastLatchData(false)
|
||||
{
|
||||
}
|
||||
|
||||
void Rtc::doLatch() {
|
||||
std::time_t tmp = ((dataDh & 0x40) ? haltTime : std::time(0)) - baseTime;
|
||||
|
||||
while (tmp > 0x1FF * 86400) {
|
||||
baseTime += 0x1FF * 86400;
|
||||
tmp -= 0x1FF * 86400;
|
||||
dataDh |= 0x80;
|
||||
}
|
||||
|
||||
dataDl = (tmp / 86400) & 0xFF;
|
||||
dataDh &= 0xFE;
|
||||
dataDh |= ((tmp / 86400) & 0x100) >> 8;
|
||||
tmp %= 86400;
|
||||
|
||||
dataH = tmp / 3600;
|
||||
tmp %= 3600;
|
||||
|
||||
dataM = tmp / 60;
|
||||
tmp %= 60;
|
||||
|
||||
dataS = tmp;
|
||||
}
|
||||
|
||||
void Rtc::doSwapActive() {
|
||||
if (!enabled || index > 4) {
|
||||
activeData = NULL;
|
||||
activeSet = NULL;
|
||||
} else switch (index) {
|
||||
case 0x00:
|
||||
activeData = &dataS;
|
||||
activeSet = &Rtc::setS;
|
||||
break;
|
||||
case 0x01:
|
||||
activeData = &dataM;
|
||||
activeSet = &Rtc::setM;
|
||||
break;
|
||||
case 0x02:
|
||||
activeData = &dataH;
|
||||
activeSet = &Rtc::setH;
|
||||
break;
|
||||
case 0x03:
|
||||
activeData = &dataDl;
|
||||
activeSet = &Rtc::setDl;
|
||||
break;
|
||||
case 0x04:
|
||||
activeData = &dataDh;
|
||||
activeSet = &Rtc::setDh;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Rtc::saveState(SaveState &state) const {
|
||||
state.rtc.baseTime = baseTime;
|
||||
state.rtc.haltTime = haltTime;
|
||||
state.rtc.dataDh = dataDh;
|
||||
state.rtc.dataDl = dataDl;
|
||||
state.rtc.dataH = dataH;
|
||||
state.rtc.dataM = dataM;
|
||||
state.rtc.dataS = dataS;
|
||||
state.rtc.lastLatchData = lastLatchData;
|
||||
}
|
||||
|
||||
void Rtc::loadState(const SaveState &state) {
|
||||
baseTime = state.rtc.baseTime;
|
||||
haltTime = state.rtc.haltTime;
|
||||
dataDh = state.rtc.dataDh;
|
||||
dataDl = state.rtc.dataDl;
|
||||
dataH = state.rtc.dataH;
|
||||
dataM = state.rtc.dataM;
|
||||
dataS = state.rtc.dataS;
|
||||
lastLatchData = state.rtc.lastLatchData;
|
||||
|
||||
doSwapActive();
|
||||
}
|
||||
|
||||
void Rtc::setDh(const unsigned new_dh) {
|
||||
const std::time_t unixtime = (dataDh & 0x40) ? haltTime : std::time(0);
|
||||
const std::time_t old_highdays = ((unixtime - baseTime) / 86400) & 0x100;
|
||||
baseTime += old_highdays * 86400;
|
||||
baseTime -= ((new_dh & 0x1) << 8) * 86400;
|
||||
|
||||
if ((dataDh ^ new_dh) & 0x40) {
|
||||
if (new_dh & 0x40)
|
||||
haltTime = std::time(0);
|
||||
else
|
||||
baseTime += std::time(0) - haltTime;
|
||||
}
|
||||
}
|
||||
|
||||
void Rtc::setDl(const unsigned new_lowdays) {
|
||||
const std::time_t unixtime = (dataDh & 0x40) ? haltTime : std::time(0);
|
||||
const std::time_t old_lowdays = ((unixtime - baseTime) / 86400) & 0xFF;
|
||||
baseTime += old_lowdays * 86400;
|
||||
baseTime -= new_lowdays * 86400;
|
||||
}
|
||||
|
||||
void Rtc::setH(const unsigned new_hours) {
|
||||
const std::time_t unixtime = (dataDh & 0x40) ? haltTime : std::time(0);
|
||||
const std::time_t old_hours = ((unixtime - baseTime) / 3600) % 24;
|
||||
baseTime += old_hours * 3600;
|
||||
baseTime -= new_hours * 3600;
|
||||
}
|
||||
|
||||
void Rtc::setM(const unsigned new_minutes) {
|
||||
const std::time_t unixtime = (dataDh & 0x40) ? haltTime : std::time(0);
|
||||
const std::time_t old_minutes = ((unixtime - baseTime) / 60) % 60;
|
||||
baseTime += old_minutes * 60;
|
||||
baseTime -= new_minutes * 60;
|
||||
}
|
||||
|
||||
void Rtc::setS(const unsigned new_seconds) {
|
||||
const std::time_t unixtime = (dataDh & 0x40) ? haltTime : std::time(0);
|
||||
baseTime += (unixtime - baseTime) % 60;
|
||||
baseTime -= new_seconds;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef RTC_H
|
||||
#define RTC_H
|
||||
|
||||
#include <ctime>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct SaveState;
|
||||
|
||||
class Rtc {
|
||||
private:
|
||||
unsigned char *activeData;
|
||||
void (Rtc::*activeSet)(unsigned);
|
||||
std::time_t baseTime;
|
||||
std::time_t haltTime;
|
||||
unsigned char index;
|
||||
unsigned char dataDh;
|
||||
unsigned char dataDl;
|
||||
unsigned char dataH;
|
||||
unsigned char dataM;
|
||||
unsigned char dataS;
|
||||
bool enabled;
|
||||
bool lastLatchData;
|
||||
|
||||
void doLatch();
|
||||
void doSwapActive();
|
||||
void setDh(unsigned new_dh);
|
||||
void setDl(unsigned new_lowdays);
|
||||
void setH(unsigned new_hours);
|
||||
void setM(unsigned new_minutes);
|
||||
void setS(unsigned new_seconds);
|
||||
|
||||
public:
|
||||
Rtc();
|
||||
|
||||
const unsigned char* getActive() const { return activeData; }
|
||||
std::time_t& getBaseTime() { return baseTime; }
|
||||
|
||||
void setBaseTime(const std::time_t baseTime) {
|
||||
this->baseTime = baseTime;
|
||||
// doLatch();
|
||||
}
|
||||
|
||||
void latch(const unsigned data) {
|
||||
if (!lastLatchData && data == 1)
|
||||
doLatch();
|
||||
|
||||
lastLatchData = data;
|
||||
}
|
||||
|
||||
void saveState(SaveState &state) const;
|
||||
void loadState(const SaveState &state);
|
||||
|
||||
void set(const bool enabled, unsigned bank) {
|
||||
bank &= 0xF;
|
||||
bank -= 8;
|
||||
|
||||
this->enabled = enabled;
|
||||
this->index = bank;
|
||||
|
||||
doSwapActive();
|
||||
}
|
||||
|
||||
void write(const unsigned data) {
|
||||
// if (activeSet)
|
||||
(this->*activeSet)(data);
|
||||
*activeData = data;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,160 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include "mem/cartridge.h"
|
||||
#include "interrupter.h"
|
||||
#include "pakinfo.h"
|
||||
#include "sound.h"
|
||||
#include "tima.h"
|
||||
#include "video.h"
|
||||
|
||||
namespace gambatte {
|
||||
class InputGetter;
|
||||
class FilterInfo;
|
||||
|
||||
class Memory {
|
||||
Cartridge cart;
|
||||
unsigned char ioamhram[0x200];
|
||||
|
||||
InputGetter *getInput;
|
||||
unsigned long divLastUpdate;
|
||||
unsigned long lastOamDmaUpdate;
|
||||
|
||||
InterruptRequester intreq;
|
||||
Tima tima;
|
||||
LCD display;
|
||||
PSG sound;
|
||||
Interrupter interrupter;
|
||||
|
||||
unsigned short dmaSource;
|
||||
unsigned short dmaDestination;
|
||||
unsigned char oamDmaPos;
|
||||
unsigned char serialCnt;
|
||||
bool blanklcd;
|
||||
|
||||
void updateInput();
|
||||
void decEventCycles(MemEventId eventId, unsigned long dec);
|
||||
|
||||
void oamDmaInitSetup();
|
||||
void updateOamDma(unsigned long cycleCounter);
|
||||
void startOamDma(unsigned long cycleCounter);
|
||||
void endOamDma(unsigned long cycleCounter);
|
||||
const unsigned char * oamDmaSrcPtr() const;
|
||||
|
||||
unsigned nontrivial_ff_read(unsigned P, unsigned long cycleCounter);
|
||||
unsigned nontrivial_read(unsigned P, unsigned long cycleCounter);
|
||||
void nontrivial_ff_write(unsigned P, unsigned data, unsigned long cycleCounter);
|
||||
void nontrivial_write(unsigned P, unsigned data, unsigned long cycleCounter);
|
||||
|
||||
void updateSerial(unsigned long cc);
|
||||
void updateTimaIrq(unsigned long cc);
|
||||
void updateIrqs(unsigned long cc);
|
||||
|
||||
bool isDoubleSpeed() const { return display.isDoubleSpeed(); }
|
||||
|
||||
public:
|
||||
explicit Memory(const Interrupter &interrupter);
|
||||
|
||||
//bool loaded() const { return cart.loaded(); }
|
||||
char const * romTitle() const { return cart.romTitle(); }
|
||||
PakInfo const pakInfo(bool multicartCompat) const { return cart.pakInfo(multicartCompat); }
|
||||
|
||||
void setStatePtrs(SaveState &state);
|
||||
unsigned long saveState(SaveState &state, unsigned long cc);
|
||||
void loadState(const SaveState &state/*, unsigned long oldCc*/);
|
||||
//void loadSavedata() { cart.loadSavedata(); }
|
||||
//void saveSavedata() { cart.saveSavedata(); }
|
||||
//const std::string saveBasePath() const { return cart.saveBasePath(); }
|
||||
void *savedata_ptr() { return cart.savedata_ptr(); }
|
||||
unsigned savedata_size() { return cart.savedata_size(); }
|
||||
void *rtcdata_ptr() { return cart.rtcdata_ptr(); }
|
||||
unsigned rtcdata_size() { return cart.rtcdata_size(); }
|
||||
|
||||
void setOsdElement(std::auto_ptr<OsdElement> osdElement) {
|
||||
display.setOsdElement(osdElement);
|
||||
}
|
||||
|
||||
unsigned long stop(unsigned long cycleCounter);
|
||||
bool isCgb() const { return display.isCgb(); }
|
||||
bool ime() const { return intreq.ime(); }
|
||||
bool halted() const { return intreq.halted(); }
|
||||
unsigned long nextEventTime() const { return intreq.minEventTime(); }
|
||||
|
||||
bool isActive() const { return intreq.eventTime(END) != DISABLED_TIME; }
|
||||
|
||||
long cyclesSinceBlit(const unsigned long cc) const {
|
||||
return cc < intreq.eventTime(BLIT) ? -1 : static_cast<long>((cc - intreq.eventTime(BLIT)) >> isDoubleSpeed());
|
||||
}
|
||||
|
||||
void halt() { intreq.halt(); }
|
||||
void ei(unsigned long cycleCounter) { if (!ime()) { intreq.ei(cycleCounter); } }
|
||||
|
||||
void di() { intreq.di(); }
|
||||
|
||||
unsigned ff_read(const unsigned P, const unsigned long cycleCounter) {
|
||||
return P < 0xFF80 ? nontrivial_ff_read(P, cycleCounter) : ioamhram[P - 0xFE00];
|
||||
}
|
||||
|
||||
unsigned read(const unsigned P, const unsigned long cycleCounter) {
|
||||
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
|
||||
}
|
||||
|
||||
void write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (cart.wmem(P >> 12)) {
|
||||
cart.wmem(P >> 12)[P] = data;
|
||||
} else
|
||||
nontrivial_write(P, data, cycleCounter);
|
||||
}
|
||||
|
||||
void ff_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (P - 0xFF80u < 0x7Fu) {
|
||||
ioamhram[P - 0xFE00] = data;
|
||||
} else
|
||||
nontrivial_ff_write(P, data, cycleCounter);
|
||||
}
|
||||
|
||||
unsigned long event(unsigned long cycleCounter);
|
||||
unsigned long resetCounters(unsigned long cycleCounter);
|
||||
|
||||
LoadRes loadROM(const std::string &romfile, bool forceDmg, bool multicartCompat);
|
||||
void setSaveDir(const std::string &dir) { cart.setSaveDir(dir); }
|
||||
|
||||
void setInputGetter(InputGetter *getInput) {
|
||||
this->getInput = getInput;
|
||||
}
|
||||
|
||||
void setEndtime(unsigned long cc, unsigned long inc);
|
||||
|
||||
void setSoundBuffer(uint_least32_t *const buf) { sound.setBuffer(buf); }
|
||||
unsigned fillSoundBuffer(unsigned long cc);
|
||||
|
||||
void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) {
|
||||
display.setVideoBuffer(videoBuf, pitch);
|
||||
}
|
||||
|
||||
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32);
|
||||
void setGameGenie(const std::string &codes) { cart.setGameGenie(codes); }
|
||||
void setGameShark(const std::string &codes) { interrupter.setGameShark(codes); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,147 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef MINKEEPER_H
|
||||
#define MINKEEPER_H
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace MinKeeperUtil {
|
||||
template<int n> struct CeiledLog2 { enum { R = 1 + CeiledLog2<(n + 1) / 2>::R }; };
|
||||
template<> struct CeiledLog2<1> { enum { R = 0 }; };
|
||||
|
||||
template<int v, int n> struct RoundedDiv2n { enum { R = RoundedDiv2n<(v + 1) / 2, n - 1>::R }; };
|
||||
template<int v> struct RoundedDiv2n<v,1> { enum { R = v }; };
|
||||
|
||||
template<template<int> class T, int n> struct Sum { enum { R = T<n-1>::R + Sum<T, n-1>::R }; };
|
||||
template<template<int> class T> struct Sum<T,0> { enum { R = 0 }; };
|
||||
}
|
||||
|
||||
// Keeps track of minimum value identified by id as values change.
|
||||
// Higher ids prioritized (as min value) if values are equal. Can easily be reversed by swapping < for <=.
|
||||
// Higher ids can be faster to change when the number of ids isn't a power of 2.
|
||||
// Thus the ones that change more frequently should have higher ids if priority allows it.
|
||||
template<int ids>
|
||||
class MinKeeper {
|
||||
enum { LEVELS = MinKeeperUtil::CeiledLog2<ids>::R };
|
||||
template<int l> struct Num { enum { R = MinKeeperUtil::RoundedDiv2n<ids, LEVELS + 1 - l>::R }; };
|
||||
template<int l> struct Sum { enum { R = MinKeeperUtil::Sum<Num, l>::R }; };
|
||||
|
||||
template<int id, int level>
|
||||
struct UpdateValue {
|
||||
enum { P = Sum<level-1>::R + id };
|
||||
enum { C0 = Sum<level>::R + id * 2 };
|
||||
|
||||
static void updateValue(MinKeeper<ids> &m) {
|
||||
// GCC 4.3 generates better code with the ternary operator on i386.
|
||||
m.a[P] = (id * 2 + 1 == Num<level>::R || m.values[m.a[C0]] < m.values[m.a[C0 + 1]]) ? m.a[C0] : m.a[C0 + 1];
|
||||
UpdateValue<id / 2, level - 1>::updateValue(m);
|
||||
}
|
||||
};
|
||||
|
||||
template<int id>
|
||||
struct UpdateValue<id,0> {
|
||||
static void updateValue(MinKeeper<ids> &m) {
|
||||
m.minValue_ = m.values[m.a[0]];
|
||||
}
|
||||
};
|
||||
|
||||
class UpdateValueLut {
|
||||
template<int id, int dummy> struct FillLut {
|
||||
static void fillLut(UpdateValueLut & l) {
|
||||
l.lut_[id] = updateValue<id>;
|
||||
FillLut<id-1,dummy>::fillLut(l);
|
||||
}
|
||||
};
|
||||
|
||||
template<int dummy> struct FillLut<-1,dummy> {
|
||||
static void fillLut(UpdateValueLut &) {}
|
||||
};
|
||||
|
||||
void (*lut_[Num<LEVELS-1>::R])(MinKeeper<ids>&);
|
||||
|
||||
public:
|
||||
UpdateValueLut() { FillLut<Num<LEVELS-1>::R-1,0>::fillLut(*this); }
|
||||
void call(int id, MinKeeper<ids> &mk) const { lut_[id](mk); }
|
||||
};
|
||||
|
||||
static UpdateValueLut updateValueLut;
|
||||
unsigned long values[ids];
|
||||
unsigned long minValue_;
|
||||
int a[Sum<LEVELS>::R];
|
||||
|
||||
template<int id> static void updateValue(MinKeeper<ids> &m);
|
||||
|
||||
public:
|
||||
explicit MinKeeper(unsigned long initValue = 0xFFFFFFFF);
|
||||
|
||||
int min() const { return a[0]; }
|
||||
unsigned long minValue() const { return minValue_; }
|
||||
|
||||
template<int id>
|
||||
void setValue(const unsigned long cnt) {
|
||||
values[id] = cnt;
|
||||
updateValue<id / 2>(*this);
|
||||
}
|
||||
|
||||
void setValue(const int id, const unsigned long cnt) {
|
||||
values[id] = cnt;
|
||||
updateValueLut.call(id >> 1, *this);
|
||||
}
|
||||
|
||||
unsigned long value(const int id) const { return values[id]; }
|
||||
};
|
||||
|
||||
template<int ids> typename MinKeeper<ids>::UpdateValueLut MinKeeper<ids>::updateValueLut;
|
||||
|
||||
template<int ids>
|
||||
MinKeeper<ids>::MinKeeper(const unsigned long initValue) {
|
||||
std::fill(values, values + ids, initValue);
|
||||
|
||||
for (int i = 0; i < Num<LEVELS-1>::R; ++i) {
|
||||
a[Sum<LEVELS-1>::R + i] = (i * 2 + 1 == ids || values[i * 2] < values[i * 2 + 1]) ? i * 2 : i * 2 + 1;
|
||||
}
|
||||
|
||||
int n = Num<LEVELS-1>::R;
|
||||
int off = Sum<LEVELS-1>::R;
|
||||
|
||||
while (off) {
|
||||
const int pn = (n + 1) >> 1;
|
||||
const int poff = off - pn;
|
||||
|
||||
for (int i = 0; i < pn; ++i) {
|
||||
a[poff + i] = (i * 2 + 1 == n ||
|
||||
values[a[off + i * 2]] < values[a[off + i * 2 + 1]]) ?
|
||||
a[off + i * 2] : a[off + i * 2 + 1];
|
||||
}
|
||||
|
||||
off = poff;
|
||||
n = pn;
|
||||
}
|
||||
|
||||
minValue_ = values[a[0]];
|
||||
}
|
||||
|
||||
template<int ids>
|
||||
template<int id>
|
||||
void MinKeeper<ids>::updateValue(MinKeeper<ids> &m) {
|
||||
m.a[Sum<LEVELS-1>::R + id] = (id * 2 + 1 == ids || m.values[id * 2] < m.values[id * 2 + 1]) ? id * 2 : id * 2 + 1;
|
||||
UpdateValue<id / 2, LEVELS-1>::updateValue(m);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,68 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef OSD_ELEMENT_H
|
||||
#define OSD_ELEMENT_H
|
||||
|
||||
#include "gbint.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class OsdElement {
|
||||
public:
|
||||
enum Opacity { SEVEN_EIGHTHS, THREE_FOURTHS };
|
||||
|
||||
private:
|
||||
Opacity opacity_;
|
||||
unsigned x_;
|
||||
unsigned y_;
|
||||
unsigned w_;
|
||||
unsigned h_;
|
||||
|
||||
protected:
|
||||
explicit OsdElement(unsigned x = 0, unsigned y = 0, unsigned w = 0, unsigned h = 0, Opacity opacity = SEVEN_EIGHTHS)
|
||||
: opacity_(opacity), x_(x), y_(y), w_(w), h_(h)
|
||||
{
|
||||
}
|
||||
|
||||
void setPos(unsigned x, unsigned y) {
|
||||
x_ = x;
|
||||
y_ = y;
|
||||
}
|
||||
|
||||
void setSize(unsigned w, unsigned h) {
|
||||
w_ = w;
|
||||
h_ = h;
|
||||
}
|
||||
|
||||
void setOpacity(Opacity opacity) { opacity_ = opacity; }
|
||||
|
||||
public:
|
||||
virtual ~OsdElement() {}
|
||||
unsigned x() const { return x_; }
|
||||
unsigned y() const { return y_; }
|
||||
unsigned w() const { return w_; }
|
||||
unsigned h() const { return h_; }
|
||||
Opacity opacity() const { return opacity_; }
|
||||
|
||||
virtual const uint_least32_t* update() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,182 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "sound.h"
|
||||
#include "savestate.h"
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
/*
|
||||
Frame Sequencer
|
||||
|
||||
Step Length Ctr Vol Env Sweep
|
||||
- - - - - - - - - - - - - - - - - - - -
|
||||
0 Clock - Clock
|
||||
S 1 - Clock -
|
||||
2 Clock - -
|
||||
3 - - -
|
||||
4 Clock - Clock
|
||||
5 - - -
|
||||
6 Clock - -
|
||||
7 - - -
|
||||
- - - - - - - - - - - - - - - - - - - -
|
||||
Rate 256 Hz 64 Hz 128 Hz
|
||||
|
||||
S) start step on sound power on.
|
||||
*/
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
PSG::PSG()
|
||||
: buffer(0),
|
||||
lastUpdate(0),
|
||||
soVol(0),
|
||||
rsum(0x8000), // initialize to 0x8000 to prevent borrows from high word, xor away later
|
||||
bufferPos(0),
|
||||
enabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
void PSG::init(const bool cgb) {
|
||||
ch1.init(cgb);
|
||||
ch2.init(cgb);
|
||||
ch3.init(cgb);
|
||||
ch4.init(cgb);
|
||||
}
|
||||
|
||||
void PSG::reset() {
|
||||
ch1.reset();
|
||||
ch2.reset();
|
||||
ch3.reset();
|
||||
ch4.reset();
|
||||
}
|
||||
|
||||
void PSG::setStatePtrs(SaveState &state) {
|
||||
ch3.setStatePtrs(state);
|
||||
}
|
||||
|
||||
void PSG::saveState(SaveState &state) {
|
||||
ch1.saveState(state);
|
||||
ch2.saveState(state);
|
||||
ch3.saveState(state);
|
||||
ch4.saveState(state);
|
||||
}
|
||||
|
||||
void PSG::loadState(const SaveState &state) {
|
||||
ch1.loadState(state);
|
||||
ch2.loadState(state);
|
||||
ch3.loadState(state);
|
||||
ch4.loadState(state);
|
||||
|
||||
lastUpdate = state.cpu.cycleCounter;
|
||||
set_so_volume(state.mem.ioamhram.get()[0x124]);
|
||||
map_so(state.mem.ioamhram.get()[0x125]);
|
||||
enabled = state.mem.ioamhram.get()[0x126] >> 7 & 1;
|
||||
}
|
||||
|
||||
void PSG::accumulate_channels(const unsigned long cycles) {
|
||||
uint_least32_t *const buf = buffer + bufferPos;
|
||||
|
||||
std::memset(buf, 0, cycles * sizeof(uint_least32_t));
|
||||
ch1.update(buf, soVol, cycles);
|
||||
ch2.update(buf, soVol, cycles);
|
||||
ch3.update(buf, soVol, cycles);
|
||||
ch4.update(buf, soVol, cycles);
|
||||
}
|
||||
|
||||
void PSG::generate_samples(const unsigned long cycleCounter, const unsigned doubleSpeed) {
|
||||
const unsigned long cycles = (cycleCounter - lastUpdate) >> (1 + doubleSpeed);
|
||||
lastUpdate += cycles << (1 + doubleSpeed);
|
||||
|
||||
if (cycles)
|
||||
accumulate_channels(cycles);
|
||||
|
||||
bufferPos += cycles;
|
||||
}
|
||||
|
||||
void PSG::resetCounter(const unsigned long newCc, const unsigned long oldCc, const unsigned doubleSpeed) {
|
||||
generate_samples(oldCc, doubleSpeed);
|
||||
lastUpdate = newCc - (oldCc - lastUpdate);
|
||||
}
|
||||
|
||||
unsigned PSG::fillBuffer() {
|
||||
uint_least32_t sum = rsum;
|
||||
uint_least32_t *b = buffer;
|
||||
unsigned n = bufferPos;
|
||||
|
||||
if (unsigned n2 = n >> 3) {
|
||||
n -= n2 << 3;
|
||||
|
||||
do {
|
||||
sum += b[0];
|
||||
b[0] = sum ^ 0x8000;
|
||||
sum += b[1];
|
||||
b[1] = sum ^ 0x8000;
|
||||
sum += b[2];
|
||||
b[2] = sum ^ 0x8000;
|
||||
sum += b[3];
|
||||
b[3] = sum ^ 0x8000;
|
||||
sum += b[4];
|
||||
b[4] = sum ^ 0x8000;
|
||||
sum += b[5];
|
||||
b[5] = sum ^ 0x8000;
|
||||
sum += b[6];
|
||||
b[6] = sum ^ 0x8000;
|
||||
sum += b[7];
|
||||
b[7] = sum ^ 0x8000;
|
||||
|
||||
b += 8;
|
||||
} while (--n2);
|
||||
}
|
||||
|
||||
while (n--) {
|
||||
sum += *b;
|
||||
*b++ = sum ^ 0x8000; // xor away the initial rsum value of 0x8000 (which prevents borrows from the high word) from the low word
|
||||
}
|
||||
|
||||
rsum = sum;
|
||||
|
||||
return bufferPos;
|
||||
}
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
static const unsigned long so1Mul = 0x00000001;
|
||||
static const unsigned long so2Mul = 0x00010000;
|
||||
#else
|
||||
static const unsigned long so1Mul = 0x00010000;
|
||||
static const unsigned long so2Mul = 0x00000001;
|
||||
#endif
|
||||
|
||||
void PSG::set_so_volume(const unsigned nr50) {
|
||||
soVol = (((nr50 & 0x7) + 1) * so1Mul + ((nr50 >> 4 & 0x7) + 1) * so2Mul) * 64;
|
||||
}
|
||||
|
||||
void PSG::map_so(const unsigned nr51) {
|
||||
const unsigned long tmp = nr51 * so1Mul + (nr51 >> 4) * so2Mul;
|
||||
|
||||
ch1.setSo((tmp & 0x00010001) * 0xFFFF);
|
||||
ch2.setSo((tmp >> 1 & 0x00010001) * 0xFFFF);
|
||||
ch3.setSo((tmp >> 2 & 0x00010001) * 0xFFFF);
|
||||
ch4.setSo((tmp >> 3 & 0x00010001) * 0xFFFF);
|
||||
}
|
||||
|
||||
unsigned PSG::getStatus() const {
|
||||
return ch1.isActive() | ch2.isActive() << 1 | ch3.isActive() << 2 | ch4.isActive() << 3;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SOUND_H
|
||||
#define SOUND_H
|
||||
|
||||
#include "sound/channel1.h"
|
||||
#include "sound/channel2.h"
|
||||
#include "sound/channel3.h"
|
||||
#include "sound/channel4.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class PSG {
|
||||
Channel1 ch1;
|
||||
Channel2 ch2;
|
||||
Channel3 ch3;
|
||||
Channel4 ch4;
|
||||
|
||||
uint_least32_t *buffer;
|
||||
|
||||
unsigned long lastUpdate;
|
||||
unsigned long soVol;
|
||||
|
||||
uint_least32_t rsum;
|
||||
|
||||
unsigned bufferPos;
|
||||
|
||||
bool enabled;
|
||||
|
||||
void accumulate_channels(unsigned long cycles);
|
||||
|
||||
public:
|
||||
PSG();
|
||||
void init(bool cgb);
|
||||
void reset();
|
||||
void setStatePtrs(SaveState &state);
|
||||
void saveState(SaveState &state);
|
||||
void loadState(const SaveState &state);
|
||||
|
||||
void generate_samples(unsigned long cycleCounter, unsigned doubleSpeed);
|
||||
void resetCounter(unsigned long newCc, unsigned long oldCc, unsigned doubleSpeed);
|
||||
unsigned fillBuffer();
|
||||
void setBuffer(uint_least32_t *const buf) { buffer = buf; bufferPos = 0; }
|
||||
|
||||
bool isEnabled() const { return enabled; }
|
||||
void setEnabled(bool value) { enabled = value; }
|
||||
|
||||
void set_nr10(unsigned data) { ch1.setNr0(data); }
|
||||
void set_nr11(unsigned data) { ch1.setNr1(data); }
|
||||
void set_nr12(unsigned data) { ch1.setNr2(data); }
|
||||
void set_nr13(unsigned data) { ch1.setNr3(data); }
|
||||
void set_nr14(unsigned data) { ch1.setNr4(data); }
|
||||
|
||||
void set_nr21(unsigned data) { ch2.setNr1(data); }
|
||||
void set_nr22(unsigned data) { ch2.setNr2(data); }
|
||||
void set_nr23(unsigned data) { ch2.setNr3(data); }
|
||||
void set_nr24(unsigned data) { ch2.setNr4(data); }
|
||||
|
||||
void set_nr30(unsigned data) { ch3.setNr0(data); }
|
||||
void set_nr31(unsigned data) { ch3.setNr1(data); }
|
||||
void set_nr32(unsigned data) { ch3.setNr2(data); }
|
||||
void set_nr33(unsigned data) { ch3.setNr3(data); }
|
||||
void set_nr34(unsigned data) { ch3.setNr4(data); }
|
||||
unsigned waveRamRead(unsigned index) const { return ch3.waveRamRead(index); }
|
||||
void waveRamWrite(unsigned index, unsigned data) { ch3.waveRamWrite(index, data); }
|
||||
|
||||
void set_nr41(unsigned data) { ch4.setNr1(data); }
|
||||
void set_nr42(unsigned data) { ch4.setNr2(data); }
|
||||
void set_nr43(unsigned data) { ch4.setNr3(data); }
|
||||
void set_nr44(unsigned data) { ch4.setNr4(data); }
|
||||
|
||||
void set_so_volume(unsigned nr50);
|
||||
void map_so(unsigned nr51);
|
||||
unsigned getStatus() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,262 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aam�s *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "channel1.h"
|
||||
#include "../savestate.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
Channel1::SweepUnit::SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit) :
|
||||
disableMaster(disabler),
|
||||
dutyUnit(dutyUnit),
|
||||
shadow(0),
|
||||
nr0(0),
|
||||
negging(false)
|
||||
{}
|
||||
|
||||
unsigned Channel1::SweepUnit::calcFreq() {
|
||||
unsigned freq = shadow >> (nr0 & 0x07);
|
||||
|
||||
if (nr0 & 0x08) {
|
||||
freq = shadow - freq;
|
||||
negging = true;
|
||||
} else
|
||||
freq = shadow + freq;
|
||||
|
||||
if (freq & 2048)
|
||||
disableMaster();
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
void Channel1::SweepUnit::event() {
|
||||
const unsigned long period = nr0 >> 4 & 0x07;
|
||||
|
||||
if (period) {
|
||||
const unsigned freq = calcFreq();
|
||||
|
||||
if (!(freq & 2048) && (nr0 & 0x07)) {
|
||||
shadow = freq;
|
||||
dutyUnit.setFreq(freq, counter);
|
||||
calcFreq();
|
||||
}
|
||||
|
||||
counter += period << 14;
|
||||
} else
|
||||
counter += 8ul << 14;
|
||||
}
|
||||
|
||||
void Channel1::SweepUnit::nr0Change(const unsigned newNr0) {
|
||||
if (negging && !(newNr0 & 0x08))
|
||||
disableMaster();
|
||||
|
||||
nr0 = newNr0;
|
||||
}
|
||||
|
||||
void Channel1::SweepUnit::nr4Init(const unsigned long cc) {
|
||||
negging = false;
|
||||
shadow = dutyUnit.getFreq();
|
||||
|
||||
const unsigned period = nr0 >> 4 & 0x07;
|
||||
const unsigned shift = nr0 & 0x07;
|
||||
|
||||
if (period | shift)
|
||||
counter = ((cc >> 14) + (period ? period : 8)) << 14;
|
||||
else
|
||||
counter = COUNTER_DISABLED;
|
||||
|
||||
if (shift)
|
||||
calcFreq();
|
||||
}
|
||||
|
||||
void Channel1::SweepUnit::reset() {
|
||||
counter = COUNTER_DISABLED;
|
||||
}
|
||||
|
||||
void Channel1::SweepUnit::saveState(SaveState &state) const {
|
||||
state.spu.ch1.sweep.counter = counter;
|
||||
state.spu.ch1.sweep.shadow = shadow;
|
||||
state.spu.ch1.sweep.nr0 = nr0;
|
||||
state.spu.ch1.sweep.negging = negging;
|
||||
}
|
||||
|
||||
void Channel1::SweepUnit::loadState(const SaveState &state) {
|
||||
counter = std::max(state.spu.ch1.sweep.counter, state.spu.cycleCounter);
|
||||
shadow = state.spu.ch1.sweep.shadow;
|
||||
nr0 = state.spu.ch1.sweep.nr0;
|
||||
negging = state.spu.ch1.sweep.negging;
|
||||
}
|
||||
|
||||
Channel1::Channel1() :
|
||||
staticOutputTest(*this, dutyUnit),
|
||||
disableMaster(master, dutyUnit),
|
||||
lengthCounter(disableMaster, 0x3F),
|
||||
envelopeUnit(staticOutputTest),
|
||||
sweepUnit(disableMaster, dutyUnit),
|
||||
cycleCounter(0),
|
||||
soMask(0),
|
||||
prevOut(0),
|
||||
nr4(0),
|
||||
master(false)
|
||||
{
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel1::setEvent() {
|
||||
// nextEventUnit = &dutyUnit;
|
||||
// if (sweepUnit.getCounter() < nextEventUnit->getCounter())
|
||||
nextEventUnit = &sweepUnit;
|
||||
if (envelopeUnit.getCounter() < nextEventUnit->getCounter())
|
||||
nextEventUnit = &envelopeUnit;
|
||||
if (lengthCounter.getCounter() < nextEventUnit->getCounter())
|
||||
nextEventUnit = &lengthCounter;
|
||||
}
|
||||
|
||||
void Channel1::setNr0(const unsigned data) {
|
||||
sweepUnit.nr0Change(data);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel1::setNr1(const unsigned data) {
|
||||
lengthCounter.nr1Change(data, nr4, cycleCounter);
|
||||
dutyUnit.nr1Change(data, cycleCounter);
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel1::setNr2(const unsigned data) {
|
||||
if (envelopeUnit.nr2Change(data))
|
||||
disableMaster();
|
||||
else
|
||||
staticOutputTest(cycleCounter);
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel1::setNr3(const unsigned data) {
|
||||
dutyUnit.nr3Change(data, cycleCounter);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel1::setNr4(const unsigned data) {
|
||||
lengthCounter.nr4Change(nr4, data, cycleCounter);
|
||||
|
||||
nr4 = data;
|
||||
|
||||
dutyUnit.nr4Change(data, cycleCounter);
|
||||
|
||||
if (data & 0x80) { //init-bit
|
||||
nr4 &= 0x7F;
|
||||
master = !envelopeUnit.nr4Init(cycleCounter);
|
||||
sweepUnit.nr4Init(cycleCounter);
|
||||
staticOutputTest(cycleCounter);
|
||||
}
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel1::setSo(const unsigned long soMask) {
|
||||
this->soMask = soMask;
|
||||
staticOutputTest(cycleCounter);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel1::reset() {
|
||||
cycleCounter = 0x1000 | (cycleCounter & 0xFFF); // cycleCounter >> 12 & 7 represents the frame sequencer position.
|
||||
|
||||
// lengthCounter.reset();
|
||||
dutyUnit.reset();
|
||||
envelopeUnit.reset();
|
||||
sweepUnit.reset();
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel1::init(const bool cgb) {
|
||||
lengthCounter.init(cgb);
|
||||
}
|
||||
|
||||
void Channel1::saveState(SaveState &state) {
|
||||
sweepUnit.saveState(state);
|
||||
dutyUnit.saveState(state.spu.ch1.duty, cycleCounter);
|
||||
envelopeUnit.saveState(state.spu.ch1.env);
|
||||
lengthCounter.saveState(state.spu.ch1.lcounter);
|
||||
|
||||
state.spu.cycleCounter = cycleCounter;
|
||||
state.spu.ch1.nr4 = nr4;
|
||||
state.spu.ch1.master = master;
|
||||
}
|
||||
|
||||
void Channel1::loadState(const SaveState &state) {
|
||||
sweepUnit.loadState(state);
|
||||
dutyUnit.loadState(state.spu.ch1.duty, state.mem.ioamhram.get()[0x111], state.spu.ch1.nr4, state.spu.cycleCounter);
|
||||
envelopeUnit.loadState(state.spu.ch1.env, state.mem.ioamhram.get()[0x112], state.spu.cycleCounter);
|
||||
lengthCounter.loadState(state.spu.ch1.lcounter, state.spu.cycleCounter);
|
||||
|
||||
cycleCounter = state.spu.cycleCounter;
|
||||
nr4 = state.spu.ch1.nr4;
|
||||
master = state.spu.ch1.master;
|
||||
}
|
||||
|
||||
void Channel1::update(uint_least32_t *buf, const unsigned long soBaseVol, unsigned long cycles) {
|
||||
const unsigned long outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0;
|
||||
const unsigned long outLow = outBase * (0 - 15ul);
|
||||
const unsigned long endCycles = cycleCounter + cycles;
|
||||
|
||||
for (;;) {
|
||||
const unsigned long outHigh = master ? outBase * (envelopeUnit.getVolume() * 2 - 15ul) : outLow;
|
||||
const unsigned long nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles;
|
||||
unsigned long out = dutyUnit.isHighState() ? outHigh : outLow;
|
||||
|
||||
while (dutyUnit.getCounter() <= nextMajorEvent) {
|
||||
*buf = out - prevOut;
|
||||
prevOut = out;
|
||||
buf += dutyUnit.getCounter() - cycleCounter;
|
||||
cycleCounter = dutyUnit.getCounter();
|
||||
|
||||
dutyUnit.event();
|
||||
out = dutyUnit.isHighState() ? outHigh : outLow;
|
||||
}
|
||||
|
||||
if (cycleCounter < nextMajorEvent) {
|
||||
*buf = out - prevOut;
|
||||
prevOut = out;
|
||||
buf += nextMajorEvent - cycleCounter;
|
||||
cycleCounter = nextMajorEvent;
|
||||
}
|
||||
|
||||
if (nextEventUnit->getCounter() == nextMajorEvent) {
|
||||
nextEventUnit->event();
|
||||
setEvent();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter & SoundUnit::COUNTER_MAX) {
|
||||
dutyUnit.resetCounters(cycleCounter);
|
||||
lengthCounter.resetCounters(cycleCounter);
|
||||
envelopeUnit.resetCounters(cycleCounter);
|
||||
sweepUnit.resetCounters(cycleCounter);
|
||||
|
||||
cycleCounter -= SoundUnit::COUNTER_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SOUND_CHANNEL1_H
|
||||
#define SOUND_CHANNEL1_H
|
||||
|
||||
#include "gbint.h"
|
||||
#include "master_disabler.h"
|
||||
#include "length_counter.h"
|
||||
#include "duty_unit.h"
|
||||
#include "envelope_unit.h"
|
||||
#include "static_output_tester.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct SaveState;
|
||||
|
||||
class Channel1 {
|
||||
class SweepUnit : public SoundUnit {
|
||||
MasterDisabler &disableMaster;
|
||||
DutyUnit &dutyUnit;
|
||||
unsigned short shadow;
|
||||
unsigned char nr0;
|
||||
bool negging;
|
||||
|
||||
unsigned calcFreq();
|
||||
|
||||
public:
|
||||
SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit);
|
||||
void event();
|
||||
void nr0Change(unsigned newNr0);
|
||||
void nr4Init(unsigned long cycleCounter);
|
||||
void reset();
|
||||
void saveState(SaveState &state) const;
|
||||
void loadState(const SaveState &state);
|
||||
};
|
||||
|
||||
friend class StaticOutputTester<Channel1,DutyUnit>;
|
||||
|
||||
StaticOutputTester<Channel1,DutyUnit> staticOutputTest;
|
||||
DutyMasterDisabler disableMaster;
|
||||
LengthCounter lengthCounter;
|
||||
DutyUnit dutyUnit;
|
||||
EnvelopeUnit envelopeUnit;
|
||||
SweepUnit sweepUnit;
|
||||
|
||||
SoundUnit *nextEventUnit;
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned long soMask;
|
||||
unsigned long prevOut;
|
||||
|
||||
unsigned char nr4;
|
||||
bool master;
|
||||
|
||||
void setEvent();
|
||||
|
||||
public:
|
||||
Channel1();
|
||||
void setNr0(unsigned data);
|
||||
void setNr1(unsigned data);
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data);
|
||||
void setNr4(unsigned data);
|
||||
|
||||
void setSo(unsigned long soMask);
|
||||
bool isActive() const { return master; }
|
||||
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
|
||||
void reset();
|
||||
void init(bool cgb);
|
||||
void saveState(SaveState &state);
|
||||
void loadState(const SaveState &state);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,165 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "channel2.h"
|
||||
#include "../savestate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
Channel2::Channel2() :
|
||||
staticOutputTest(*this, dutyUnit),
|
||||
disableMaster(master, dutyUnit),
|
||||
lengthCounter(disableMaster, 0x3F),
|
||||
envelopeUnit(staticOutputTest),
|
||||
cycleCounter(0),
|
||||
soMask(0),
|
||||
prevOut(0),
|
||||
nr4(0),
|
||||
master(false)
|
||||
{
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel2::setEvent() {
|
||||
// nextEventUnit = &dutyUnit;
|
||||
// if (envelopeUnit.getCounter() < nextEventUnit->getCounter())
|
||||
nextEventUnit = &envelopeUnit;
|
||||
if (lengthCounter.getCounter() < nextEventUnit->getCounter())
|
||||
nextEventUnit = &lengthCounter;
|
||||
}
|
||||
|
||||
void Channel2::setNr1(const unsigned data) {
|
||||
lengthCounter.nr1Change(data, nr4, cycleCounter);
|
||||
dutyUnit.nr1Change(data, cycleCounter);
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel2::setNr2(const unsigned data) {
|
||||
if (envelopeUnit.nr2Change(data))
|
||||
disableMaster();
|
||||
else
|
||||
staticOutputTest(cycleCounter);
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel2::setNr3(const unsigned data) {
|
||||
dutyUnit.nr3Change(data, cycleCounter);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel2::setNr4(const unsigned data) {
|
||||
lengthCounter.nr4Change(nr4, data, cycleCounter);
|
||||
|
||||
nr4 = data;
|
||||
|
||||
if (data & 0x80) { //init-bit
|
||||
nr4 &= 0x7F;
|
||||
master = !envelopeUnit.nr4Init(cycleCounter);
|
||||
staticOutputTest(cycleCounter);
|
||||
}
|
||||
|
||||
dutyUnit.nr4Change(data, cycleCounter);
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel2::setSo(const unsigned long soMask) {
|
||||
this->soMask = soMask;
|
||||
staticOutputTest(cycleCounter);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel2::reset() {
|
||||
cycleCounter = 0x1000 | (cycleCounter & 0xFFF); // cycleCounter >> 12 & 7 represents the frame sequencer position.
|
||||
|
||||
// lengthCounter.reset();
|
||||
dutyUnit.reset();
|
||||
envelopeUnit.reset();
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel2::init(const bool cgb) {
|
||||
lengthCounter.init(cgb);
|
||||
}
|
||||
|
||||
void Channel2::saveState(SaveState &state) {
|
||||
dutyUnit.saveState(state.spu.ch2.duty, cycleCounter);
|
||||
envelopeUnit.saveState(state.spu.ch2.env);
|
||||
lengthCounter.saveState(state.spu.ch2.lcounter);
|
||||
|
||||
state.spu.ch2.nr4 = nr4;
|
||||
state.spu.ch2.master = master;
|
||||
}
|
||||
|
||||
void Channel2::loadState(const SaveState &state) {
|
||||
dutyUnit.loadState(state.spu.ch2.duty, state.mem.ioamhram.get()[0x116], state.spu.ch2.nr4,state.spu.cycleCounter);
|
||||
envelopeUnit.loadState(state.spu.ch2.env, state.mem.ioamhram.get()[0x117], state.spu.cycleCounter);
|
||||
lengthCounter.loadState(state.spu.ch2.lcounter, state.spu.cycleCounter);
|
||||
|
||||
cycleCounter = state.spu.cycleCounter;
|
||||
nr4 = state.spu.ch2.nr4;
|
||||
master = state.spu.ch2.master;
|
||||
}
|
||||
|
||||
void Channel2::update(uint_least32_t *buf, const unsigned long soBaseVol, unsigned long cycles) {
|
||||
const unsigned long outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0;
|
||||
const unsigned long outLow = outBase * (0 - 15ul);
|
||||
const unsigned long endCycles = cycleCounter + cycles;
|
||||
|
||||
for (;;) {
|
||||
const unsigned long outHigh = master ? outBase * (envelopeUnit.getVolume() * 2 - 15ul) : outLow;
|
||||
const unsigned long nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles;
|
||||
unsigned long out = dutyUnit.isHighState() ? outHigh : outLow;
|
||||
|
||||
while (dutyUnit.getCounter() <= nextMajorEvent) {
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
buf += dutyUnit.getCounter() - cycleCounter;
|
||||
cycleCounter = dutyUnit.getCounter();
|
||||
|
||||
dutyUnit.event();
|
||||
out = dutyUnit.isHighState() ? outHigh : outLow;
|
||||
}
|
||||
|
||||
if (cycleCounter < nextMajorEvent) {
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
buf += nextMajorEvent - cycleCounter;
|
||||
cycleCounter = nextMajorEvent;
|
||||
}
|
||||
|
||||
if (nextEventUnit->getCounter() == nextMajorEvent) {
|
||||
nextEventUnit->event();
|
||||
setEvent();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter & SoundUnit::COUNTER_MAX) {
|
||||
dutyUnit.resetCounters(cycleCounter);
|
||||
lengthCounter.resetCounters(cycleCounter);
|
||||
envelopeUnit.resetCounters(cycleCounter);
|
||||
|
||||
cycleCounter -= SoundUnit::COUNTER_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SOUND_CHANNEL2_H
|
||||
#define SOUND_CHANNEL2_H
|
||||
|
||||
#include "gbint.h"
|
||||
#include "length_counter.h"
|
||||
#include "duty_unit.h"
|
||||
#include "envelope_unit.h"
|
||||
#include "static_output_tester.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct SaveState;
|
||||
|
||||
class Channel2 {
|
||||
friend class StaticOutputTester<Channel2,DutyUnit>;
|
||||
|
||||
StaticOutputTester<Channel2,DutyUnit> staticOutputTest;
|
||||
DutyMasterDisabler disableMaster;
|
||||
LengthCounter lengthCounter;
|
||||
DutyUnit dutyUnit;
|
||||
EnvelopeUnit envelopeUnit;
|
||||
|
||||
SoundUnit *nextEventUnit;
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned long soMask;
|
||||
unsigned long prevOut;
|
||||
|
||||
unsigned char nr4;
|
||||
bool master;
|
||||
|
||||
void setEvent();
|
||||
|
||||
public:
|
||||
Channel2();
|
||||
void setNr1(unsigned data);
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data);
|
||||
void setNr4(unsigned data);
|
||||
|
||||
void setSo(unsigned long soMask);
|
||||
// void deactivate() { disableMaster(); setEvent(); }
|
||||
bool isActive() const { return master; }
|
||||
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
|
||||
void reset();
|
||||
void init(bool cgb);
|
||||
void saveState(SaveState &state);
|
||||
void loadState(const SaveState &state);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,207 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "channel3.h"
|
||||
#include "../savestate.h"
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
static inline unsigned toPeriod(const unsigned nr3, const unsigned nr4) {
|
||||
return 0x800 - ((nr4 << 8 & 0x700) | nr3);
|
||||
}
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
Channel3::Channel3() :
|
||||
disableMaster(master, waveCounter),
|
||||
lengthCounter(disableMaster, 0xFF),
|
||||
cycleCounter(0),
|
||||
soMask(0),
|
||||
prevOut(0),
|
||||
waveCounter(SoundUnit::COUNTER_DISABLED),
|
||||
lastReadTime(0),
|
||||
nr0(0),
|
||||
nr3(0),
|
||||
nr4(0),
|
||||
wavePos(0),
|
||||
rShift(4),
|
||||
sampleBuf(0),
|
||||
master(false),
|
||||
cgb(false)
|
||||
{}
|
||||
|
||||
void Channel3::setNr0(const unsigned data) {
|
||||
nr0 = data & 0x80;
|
||||
|
||||
if (!(data & 0x80))
|
||||
disableMaster();
|
||||
}
|
||||
|
||||
void Channel3::setNr2(const unsigned data) {
|
||||
rShift = (data >> 5 & 3U) - 1;
|
||||
|
||||
if (rShift > 3)
|
||||
rShift = 4;
|
||||
}
|
||||
|
||||
void Channel3::setNr4(const unsigned data) {
|
||||
lengthCounter.nr4Change(nr4, data, cycleCounter);
|
||||
|
||||
nr4 = data & 0x7F;
|
||||
|
||||
if (data & nr0/* & 0x80*/) {
|
||||
if (!cgb && waveCounter == cycleCounter + 1) {
|
||||
const unsigned pos = ((wavePos + 1) & 0x1F) >> 1;
|
||||
|
||||
if (pos < 4)
|
||||
waveRam[0] = waveRam[pos];
|
||||
else
|
||||
std::memcpy(waveRam, waveRam + (pos & ~3), 4);
|
||||
}
|
||||
|
||||
master = true;
|
||||
wavePos = 0;
|
||||
lastReadTime = waveCounter = cycleCounter + toPeriod(nr3, data) + 3;
|
||||
}
|
||||
}
|
||||
|
||||
void Channel3::setSo(const unsigned long soMask) {
|
||||
this->soMask = soMask;
|
||||
}
|
||||
|
||||
void Channel3::reset() {
|
||||
cycleCounter = 0x1000 | (cycleCounter & 0xFFF); // cycleCounter >> 12 & 7 represents the frame sequencer position.
|
||||
|
||||
// lengthCounter.reset();
|
||||
sampleBuf = 0;
|
||||
}
|
||||
|
||||
void Channel3::init(const bool cgb) {
|
||||
this->cgb = cgb;
|
||||
lengthCounter.init(cgb);
|
||||
}
|
||||
|
||||
void Channel3::setStatePtrs(SaveState &state) {
|
||||
state.spu.ch3.waveRam.set(waveRam, sizeof waveRam);
|
||||
}
|
||||
|
||||
void Channel3::saveState(SaveState &state) const {
|
||||
lengthCounter.saveState(state.spu.ch3.lcounter);
|
||||
|
||||
state.spu.ch3.waveCounter = waveCounter;
|
||||
state.spu.ch3.lastReadTime = lastReadTime;
|
||||
state.spu.ch3.nr3 = nr3;
|
||||
state.spu.ch3.nr4 = nr4;
|
||||
state.spu.ch3.wavePos = wavePos;
|
||||
state.spu.ch3.sampleBuf = sampleBuf;
|
||||
state.spu.ch3.master = master;
|
||||
}
|
||||
|
||||
void Channel3::loadState(const SaveState &state) {
|
||||
lengthCounter.loadState(state.spu.ch3.lcounter, state.spu.cycleCounter);
|
||||
|
||||
cycleCounter = state.spu.cycleCounter;
|
||||
waveCounter = std::max(state.spu.ch3.waveCounter, state.spu.cycleCounter);
|
||||
lastReadTime = state.spu.ch3.lastReadTime;
|
||||
nr3 = state.spu.ch3.nr3;
|
||||
nr4 = state.spu.ch3.nr4;
|
||||
wavePos = state.spu.ch3.wavePos & 0x1F;
|
||||
sampleBuf = state.spu.ch3.sampleBuf;
|
||||
master = state.spu.ch3.master;
|
||||
|
||||
nr0 = state.mem.ioamhram.get()[0x11A] & 0x80;
|
||||
setNr2(state.mem.ioamhram.get()[0x11C]);
|
||||
}
|
||||
|
||||
void Channel3::updateWaveCounter(const unsigned long cc) {
|
||||
if (cc >= waveCounter) {
|
||||
const unsigned period = toPeriod(nr3, nr4);
|
||||
const unsigned long periods = (cc - waveCounter) / period;
|
||||
|
||||
lastReadTime = waveCounter + periods * period;
|
||||
waveCounter = lastReadTime + period;
|
||||
|
||||
wavePos += periods + 1;
|
||||
wavePos &= 0x1F;
|
||||
|
||||
sampleBuf = waveRam[wavePos >> 1];
|
||||
}
|
||||
}
|
||||
|
||||
void Channel3::update(uint_least32_t *buf, const unsigned long soBaseVol, unsigned long cycles) {
|
||||
const unsigned long outBase = (nr0/* & 0x80*/) ? soBaseVol & soMask : 0;
|
||||
|
||||
if (outBase && rShift != 4) {
|
||||
const unsigned long endCycles = cycleCounter + cycles;
|
||||
|
||||
for (;;) {
|
||||
const unsigned long nextMajorEvent = lengthCounter.getCounter() < endCycles ? lengthCounter.getCounter() : endCycles;
|
||||
unsigned long out = outBase * (master ? ((sampleBuf >> (~wavePos << 2 & 4) & 0xF) >> rShift) * 2 - 15ul : 0 - 15ul);
|
||||
|
||||
while (waveCounter <= nextMajorEvent) {
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
buf += waveCounter - cycleCounter;
|
||||
cycleCounter = waveCounter;
|
||||
|
||||
lastReadTime = waveCounter;
|
||||
waveCounter += toPeriod(nr3, nr4);
|
||||
++wavePos;
|
||||
wavePos &= 0x1F;
|
||||
sampleBuf = waveRam[wavePos >> 1];
|
||||
out = outBase * (/*master ? */((sampleBuf >> (~wavePos << 2 & 4) & 0xF) >> rShift) * 2 - 15ul/* : 0 - 15ul*/);
|
||||
}
|
||||
|
||||
if (cycleCounter < nextMajorEvent) {
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
buf += nextMajorEvent - cycleCounter;
|
||||
cycleCounter = nextMajorEvent;
|
||||
}
|
||||
|
||||
if (lengthCounter.getCounter() == nextMajorEvent) {
|
||||
lengthCounter.event();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
unsigned long const out = outBase * (0 - 15ul);
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
cycleCounter += cycles;
|
||||
|
||||
while (lengthCounter.getCounter() <= cycleCounter) {
|
||||
updateWaveCounter(lengthCounter.getCounter());
|
||||
lengthCounter.event();
|
||||
}
|
||||
|
||||
updateWaveCounter(cycleCounter);
|
||||
}
|
||||
|
||||
if (cycleCounter & SoundUnit::COUNTER_MAX) {
|
||||
lengthCounter.resetCounters(cycleCounter);
|
||||
|
||||
if (waveCounter != SoundUnit::COUNTER_DISABLED)
|
||||
waveCounter -= SoundUnit::COUNTER_MAX;
|
||||
|
||||
lastReadTime -= SoundUnit::COUNTER_MAX;
|
||||
cycleCounter -= SoundUnit::COUNTER_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SOUND_CHANNEL3_H
|
||||
#define SOUND_CHANNEL3_H
|
||||
|
||||
#include "gbint.h"
|
||||
#include "master_disabler.h"
|
||||
#include "length_counter.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct SaveState;
|
||||
|
||||
class Channel3 {
|
||||
class Ch3MasterDisabler : public MasterDisabler {
|
||||
unsigned long &waveCounter;
|
||||
|
||||
public:
|
||||
Ch3MasterDisabler(bool &m, unsigned long &wC) : MasterDisabler(m), waveCounter(wC) {}
|
||||
void operator()() { MasterDisabler::operator()(); waveCounter = SoundUnit::COUNTER_DISABLED; }
|
||||
};
|
||||
|
||||
unsigned char waveRam[0x10];
|
||||
|
||||
Ch3MasterDisabler disableMaster;
|
||||
LengthCounter lengthCounter;
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned long soMask;
|
||||
unsigned long prevOut;
|
||||
unsigned long waveCounter;
|
||||
unsigned long lastReadTime;
|
||||
|
||||
unsigned char nr0;
|
||||
unsigned char nr3;
|
||||
unsigned char nr4;
|
||||
unsigned char wavePos;
|
||||
unsigned char rShift;
|
||||
unsigned char sampleBuf;
|
||||
|
||||
bool master;
|
||||
bool cgb;
|
||||
|
||||
void updateWaveCounter(unsigned long cc);
|
||||
|
||||
public:
|
||||
Channel3();
|
||||
bool isActive() const { return master; }
|
||||
void reset();
|
||||
void init(bool cgb);
|
||||
void setStatePtrs(SaveState &state);
|
||||
void saveState(SaveState &state) const;
|
||||
void loadState(const SaveState &state);
|
||||
void setNr0(unsigned data);
|
||||
void setNr1(unsigned data) { lengthCounter.nr1Change(data, nr4, cycleCounter); }
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data) { nr3 = data; }
|
||||
void setNr4(unsigned data);
|
||||
void setSo(unsigned long soMask);
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
|
||||
unsigned waveRamRead(unsigned index) const {
|
||||
if (master) {
|
||||
if (!cgb && cycleCounter != lastReadTime)
|
||||
return 0xFF;
|
||||
|
||||
index = wavePos >> 1;
|
||||
}
|
||||
|
||||
return waveRam[index];
|
||||
}
|
||||
|
||||
void waveRamWrite(unsigned index, unsigned data) {
|
||||
if (master) {
|
||||
if (!cgb && cycleCounter != lastReadTime)
|
||||
return;
|
||||
|
||||
index = wavePos >> 1;
|
||||
}
|
||||
|
||||
waveRam[index] = data;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,304 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "channel4.h"
|
||||
#include "../savestate.h"
|
||||
#include <algorithm>
|
||||
|
||||
static unsigned long toPeriod(const unsigned nr3) {
|
||||
unsigned s = (nr3 >> 4) + 3;
|
||||
unsigned r = nr3 & 7;
|
||||
|
||||
if (!r) {
|
||||
r = 1;
|
||||
--s;
|
||||
}
|
||||
|
||||
return r << s;
|
||||
}
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
Channel4::Lfsr::Lfsr() :
|
||||
backupCounter(COUNTER_DISABLED),
|
||||
reg(0xFF),
|
||||
nr3(0),
|
||||
master(false)
|
||||
{}
|
||||
|
||||
void Channel4::Lfsr::updateBackupCounter(const unsigned long cc) {
|
||||
/*if (backupCounter <= cc) {
|
||||
const unsigned long period = toPeriod(nr3);
|
||||
backupCounter = cc - (cc - backupCounter) % period + period;
|
||||
}*/
|
||||
|
||||
if (backupCounter <= cc) {
|
||||
const unsigned long period = toPeriod(nr3);
|
||||
unsigned long periods = (cc - backupCounter) / period + 1;
|
||||
|
||||
backupCounter += periods * period;
|
||||
|
||||
if (master && nr3 < 0xE0) {
|
||||
if (nr3 & 8) {
|
||||
while (periods > 6) {
|
||||
const unsigned xored = (reg << 1 ^ reg) & 0x7E;
|
||||
reg = (reg >> 6 & ~0x7E) | xored | xored << 8;
|
||||
periods -= 6;
|
||||
}
|
||||
|
||||
const unsigned xored = ((reg ^ reg >> 1) << (7 - periods)) & 0x7F;
|
||||
reg = (reg >> periods & ~(0x80 - (0x80 >> periods))) | xored | xored << 8;
|
||||
} else {
|
||||
while (periods > 15) {
|
||||
reg = reg ^ reg >> 1;
|
||||
periods -= 15;
|
||||
}
|
||||
|
||||
reg = reg >> periods | (((reg ^ reg >> 1) << (15 - periods)) & 0x7FFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Channel4::Lfsr::reviveCounter(const unsigned long cc) {
|
||||
updateBackupCounter(cc);
|
||||
counter = backupCounter;
|
||||
}
|
||||
|
||||
/*static const unsigned char nextStateDistance[0x40] = {
|
||||
6, 1, 1, 2, 2, 1, 1, 3,
|
||||
3, 1, 1, 2, 2, 1, 1, 4,
|
||||
4, 1, 1, 2, 2, 1, 1, 3,
|
||||
3, 1, 1, 2, 2, 1, 1, 5,
|
||||
5, 1, 1, 2, 2, 1, 1, 3,
|
||||
3, 1, 1, 2, 2, 1, 1, 4,
|
||||
4, 1, 1, 2, 2, 1, 1, 3,
|
||||
3, 1, 1, 2, 2, 1, 1, 6,
|
||||
};*/
|
||||
|
||||
inline void Channel4::Lfsr::event() {
|
||||
if (nr3 < 0xE0) {
|
||||
const unsigned shifted = reg >> 1;
|
||||
const unsigned xored = (reg ^ shifted) & 1;
|
||||
|
||||
reg = shifted | xored << 14;
|
||||
|
||||
if (nr3 & 8)
|
||||
reg = (reg & ~0x40) | xored << 6;
|
||||
}
|
||||
|
||||
counter += toPeriod(nr3);
|
||||
backupCounter = counter;
|
||||
|
||||
|
||||
/*if (nr3 < 0xE0) {
|
||||
const unsigned periods = nextStateDistance[reg & 0x3F];
|
||||
const unsigned xored = ((reg ^ reg >> 1) << (7 - periods)) & 0x7F;
|
||||
|
||||
reg = reg >> periods | xored << 8;
|
||||
|
||||
if (nr3 & 8)
|
||||
reg = reg & ~(0x80 - (0x80 >> periods)) | xored;
|
||||
}
|
||||
|
||||
const unsigned long period = toPeriod(nr3);
|
||||
backupCounter = counter + period;
|
||||
counter += period * nextStateDistance[reg & 0x3F];*/
|
||||
}
|
||||
|
||||
void Channel4::Lfsr::nr3Change(const unsigned newNr3, const unsigned long cc) {
|
||||
updateBackupCounter(cc);
|
||||
nr3 = newNr3;
|
||||
|
||||
// if (counter != COUNTER_DISABLED)
|
||||
// counter = backupCounter + toPeriod(nr3) * (nextStateDistance[reg & 0x3F] - 1);
|
||||
}
|
||||
|
||||
void Channel4::Lfsr::nr4Init(unsigned long cc) {
|
||||
disableMaster();
|
||||
updateBackupCounter(cc);
|
||||
master = true;
|
||||
backupCounter += 4;
|
||||
counter = backupCounter;
|
||||
// counter = backupCounter + toPeriod(nr3) * (nextStateDistance[reg & 0x3F] - 1);
|
||||
}
|
||||
|
||||
void Channel4::Lfsr::reset(const unsigned long cc) {
|
||||
nr3 = 0;
|
||||
disableMaster();
|
||||
backupCounter = cc + toPeriod(nr3);
|
||||
}
|
||||
|
||||
void Channel4::Lfsr::resetCounters(const unsigned long oldCc) {
|
||||
updateBackupCounter(oldCc);
|
||||
backupCounter -= COUNTER_MAX;
|
||||
SoundUnit::resetCounters(oldCc);
|
||||
}
|
||||
|
||||
void Channel4::Lfsr::saveState(SaveState &state, const unsigned long cc) {
|
||||
updateBackupCounter(cc);
|
||||
state.spu.ch4.lfsr.counter = backupCounter;
|
||||
state.spu.ch4.lfsr.reg = reg;
|
||||
}
|
||||
|
||||
void Channel4::Lfsr::loadState(const SaveState &state) {
|
||||
counter = backupCounter = std::max(state.spu.ch4.lfsr.counter, state.spu.cycleCounter);
|
||||
reg = state.spu.ch4.lfsr.reg;
|
||||
master = state.spu.ch4.master;
|
||||
nr3 = state.mem.ioamhram.get()[0x122];
|
||||
}
|
||||
|
||||
Channel4::Channel4() :
|
||||
staticOutputTest(*this, lfsr),
|
||||
disableMaster(master, lfsr),
|
||||
lengthCounter(disableMaster, 0x3F),
|
||||
envelopeUnit(staticOutputTest),
|
||||
cycleCounter(0),
|
||||
soMask(0),
|
||||
prevOut(0),
|
||||
nr4(0),
|
||||
master(false)
|
||||
{
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel4::setEvent() {
|
||||
// nextEventUnit = &lfsr;
|
||||
// if (envelopeUnit.getCounter() < nextEventUnit->getCounter())
|
||||
nextEventUnit = &envelopeUnit;
|
||||
if (lengthCounter.getCounter() < nextEventUnit->getCounter())
|
||||
nextEventUnit = &lengthCounter;
|
||||
}
|
||||
|
||||
void Channel4::setNr1(const unsigned data) {
|
||||
lengthCounter.nr1Change(data, nr4, cycleCounter);
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel4::setNr2(const unsigned data) {
|
||||
if (envelopeUnit.nr2Change(data))
|
||||
disableMaster();
|
||||
else
|
||||
staticOutputTest(cycleCounter);
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel4::setNr4(const unsigned data) {
|
||||
lengthCounter.nr4Change(nr4, data, cycleCounter);
|
||||
|
||||
nr4 = data;
|
||||
|
||||
if (data & 0x80) { //init-bit
|
||||
nr4 &= 0x7F;
|
||||
|
||||
master = !envelopeUnit.nr4Init(cycleCounter);
|
||||
|
||||
if (master)
|
||||
lfsr.nr4Init(cycleCounter);
|
||||
|
||||
staticOutputTest(cycleCounter);
|
||||
}
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel4::setSo(const unsigned long soMask) {
|
||||
this->soMask = soMask;
|
||||
staticOutputTest(cycleCounter);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel4::reset() {
|
||||
cycleCounter = 0x1000 | (cycleCounter & 0xFFF); // cycleCounter >> 12 & 7 represents the frame sequencer position.
|
||||
|
||||
// lengthCounter.reset();
|
||||
lfsr.reset(cycleCounter);
|
||||
envelopeUnit.reset();
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel4::init(const bool cgb) {
|
||||
lengthCounter.init(cgb);
|
||||
}
|
||||
|
||||
void Channel4::saveState(SaveState &state) {
|
||||
lfsr.saveState(state, cycleCounter);
|
||||
envelopeUnit.saveState(state.spu.ch4.env);
|
||||
lengthCounter.saveState(state.spu.ch4.lcounter);
|
||||
|
||||
state.spu.ch4.nr4 = nr4;
|
||||
state.spu.ch4.master = master;
|
||||
}
|
||||
|
||||
void Channel4::loadState(const SaveState &state) {
|
||||
lfsr.loadState(state);
|
||||
envelopeUnit.loadState(state.spu.ch4.env, state.mem.ioamhram.get()[0x121], state.spu.cycleCounter);
|
||||
lengthCounter.loadState(state.spu.ch4.lcounter, state.spu.cycleCounter);
|
||||
|
||||
cycleCounter = state.spu.cycleCounter;
|
||||
nr4 = state.spu.ch4.nr4;
|
||||
master = state.spu.ch4.master;
|
||||
}
|
||||
|
||||
void Channel4::update(uint_least32_t *buf, const unsigned long soBaseVol, unsigned long cycles) {
|
||||
const unsigned long outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0;
|
||||
const unsigned long outLow = outBase * (0 - 15ul);
|
||||
const unsigned long endCycles = cycleCounter + cycles;
|
||||
|
||||
for (;;) {
|
||||
const unsigned long outHigh = /*master ? */outBase * (envelopeUnit.getVolume() * 2 - 15ul)/* : outLow*/;
|
||||
const unsigned long nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles;
|
||||
unsigned long out = lfsr.isHighState() ? outHigh : outLow;
|
||||
|
||||
while (lfsr.getCounter() <= nextMajorEvent) {
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
buf += lfsr.getCounter() - cycleCounter;
|
||||
cycleCounter = lfsr.getCounter();
|
||||
|
||||
lfsr.event();
|
||||
out = lfsr.isHighState() ? outHigh : outLow;
|
||||
}
|
||||
|
||||
if (cycleCounter < nextMajorEvent) {
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
buf += nextMajorEvent - cycleCounter;
|
||||
cycleCounter = nextMajorEvent;
|
||||
}
|
||||
|
||||
if (nextEventUnit->getCounter() == nextMajorEvent) {
|
||||
nextEventUnit->event();
|
||||
setEvent();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
if (cycleCounter & SoundUnit::COUNTER_MAX) {
|
||||
lengthCounter.resetCounters(cycleCounter);
|
||||
lfsr.resetCounters(cycleCounter);
|
||||
envelopeUnit.resetCounters(cycleCounter);
|
||||
|
||||
cycleCounter -= SoundUnit::COUNTER_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SOUND_CHANNEL4_H
|
||||
#define SOUND_CHANNEL4_H
|
||||
|
||||
#include "gbint.h"
|
||||
#include "master_disabler.h"
|
||||
#include "length_counter.h"
|
||||
#include "envelope_unit.h"
|
||||
#include "static_output_tester.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct SaveState;
|
||||
|
||||
class Channel4 {
|
||||
class Lfsr : public SoundUnit {
|
||||
unsigned long backupCounter;
|
||||
unsigned short reg;
|
||||
unsigned char nr3;
|
||||
bool master;
|
||||
|
||||
void updateBackupCounter(unsigned long cc);
|
||||
|
||||
public:
|
||||
Lfsr();
|
||||
void event();
|
||||
bool isHighState() const { return ~reg & 1; }
|
||||
void nr3Change(unsigned newNr3, unsigned long cc);
|
||||
void nr4Init(unsigned long cc);
|
||||
void reset(unsigned long cc);
|
||||
void saveState(SaveState &state, const unsigned long cc);
|
||||
void loadState(const SaveState &state);
|
||||
void resetCounters(unsigned long oldCc);
|
||||
void disableMaster() { killCounter(); master = false; reg = 0xFF; }
|
||||
void killCounter() { counter = COUNTER_DISABLED; }
|
||||
void reviveCounter(unsigned long cc);
|
||||
};
|
||||
|
||||
class Ch4MasterDisabler : public MasterDisabler {
|
||||
Lfsr &lfsr;
|
||||
public:
|
||||
Ch4MasterDisabler(bool &m, Lfsr &lfsr) : MasterDisabler(m), lfsr(lfsr) {}
|
||||
void operator()() { MasterDisabler::operator()(); lfsr.disableMaster(); }
|
||||
};
|
||||
|
||||
friend class StaticOutputTester<Channel4,Lfsr>;
|
||||
|
||||
StaticOutputTester<Channel4,Lfsr> staticOutputTest;
|
||||
Ch4MasterDisabler disableMaster;
|
||||
LengthCounter lengthCounter;
|
||||
EnvelopeUnit envelopeUnit;
|
||||
Lfsr lfsr;
|
||||
|
||||
SoundUnit *nextEventUnit;
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned long soMask;
|
||||
unsigned long prevOut;
|
||||
|
||||
unsigned char nr4;
|
||||
bool master;
|
||||
|
||||
void setEvent();
|
||||
|
||||
public:
|
||||
Channel4();
|
||||
void setNr1(unsigned data);
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data) { lfsr.nr3Change(data, cycleCounter); /*setEvent();*/ }
|
||||
void setNr4(unsigned data);
|
||||
|
||||
void setSo(unsigned long soMask);
|
||||
bool isActive() const { return master; }
|
||||
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
|
||||
void reset();
|
||||
void init(bool cgb);
|
||||
void saveState(SaveState &state);
|
||||
void loadState(const SaveState &state);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,152 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "duty_unit.h"
|
||||
#include <algorithm>
|
||||
|
||||
static inline bool toOutState(const unsigned duty, const unsigned pos) {
|
||||
static const unsigned char duties[4] = { 0x80, 0x81, 0xE1, 0x7E };
|
||||
|
||||
return duties[duty] >> pos & 1;
|
||||
}
|
||||
|
||||
static inline unsigned toPeriod(const unsigned freq) {
|
||||
return (2048 - freq) << 1;
|
||||
}
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
void DutyUnit::updatePos(const unsigned long cc) {
|
||||
if (cc >= nextPosUpdate) {
|
||||
const unsigned long inc = (cc - nextPosUpdate) / period + 1;
|
||||
nextPosUpdate += period * inc;
|
||||
pos += inc;
|
||||
pos &= 7;
|
||||
}
|
||||
}
|
||||
|
||||
void DutyUnit::setDuty(const unsigned nr1) {
|
||||
duty = nr1 >> 6;
|
||||
high = toOutState(duty, pos);
|
||||
}
|
||||
|
||||
void DutyUnit::setCounter() {
|
||||
static const unsigned char nextStateDistance[4 * 8] = {
|
||||
6, 5, 4, 3, 2, 1, 0, 0,
|
||||
0, 5, 4, 3, 2, 1, 0, 1,
|
||||
0, 3, 2, 1, 0, 3, 2, 1,
|
||||
0, 5, 4, 3, 2, 1, 0, 1
|
||||
};
|
||||
|
||||
if (enableEvents && nextPosUpdate != COUNTER_DISABLED)
|
||||
counter = nextPosUpdate + period * nextStateDistance[(duty * 8) | pos];
|
||||
else
|
||||
counter = COUNTER_DISABLED;
|
||||
}
|
||||
|
||||
void DutyUnit::setFreq(const unsigned newFreq, const unsigned long cc) {
|
||||
updatePos(cc);
|
||||
period = toPeriod(newFreq);
|
||||
setCounter();
|
||||
}
|
||||
|
||||
void DutyUnit::event() {
|
||||
unsigned inc = period << duty;
|
||||
|
||||
if (duty == 3)
|
||||
inc -= period * 2;
|
||||
|
||||
if (!(high ^= true))
|
||||
inc = period * 8 - inc;
|
||||
|
||||
counter += inc;
|
||||
}
|
||||
|
||||
void DutyUnit::nr1Change(const unsigned newNr1, const unsigned long cc) {
|
||||
updatePos(cc);
|
||||
setDuty(newNr1);
|
||||
setCounter();
|
||||
}
|
||||
|
||||
void DutyUnit::nr3Change(const unsigned newNr3, const unsigned long cc) {
|
||||
setFreq((getFreq() & 0x700) | newNr3, cc);
|
||||
}
|
||||
|
||||
void DutyUnit::nr4Change(const unsigned newNr4, const unsigned long cc) {
|
||||
setFreq((newNr4 << 8 & 0x700) | (getFreq() & 0xFF), cc);
|
||||
|
||||
if (newNr4 & 0x80) {
|
||||
nextPosUpdate = (cc & ~1) + period;
|
||||
setCounter();
|
||||
}
|
||||
}
|
||||
|
||||
DutyUnit::DutyUnit() :
|
||||
nextPosUpdate(COUNTER_DISABLED),
|
||||
period(4096),
|
||||
pos(0),
|
||||
duty(0),
|
||||
high(false),
|
||||
enableEvents(true)
|
||||
{}
|
||||
|
||||
void DutyUnit::reset() {
|
||||
pos = 0;
|
||||
high = toOutState(duty, pos);
|
||||
nextPosUpdate = COUNTER_DISABLED;
|
||||
setCounter();
|
||||
}
|
||||
|
||||
void DutyUnit::saveState(SaveState::SPU::Duty &dstate, const unsigned long cc) {
|
||||
updatePos(cc);
|
||||
dstate.nextPosUpdate = nextPosUpdate;
|
||||
dstate.nr3 = getFreq() & 0xFF;
|
||||
dstate.pos = pos;
|
||||
}
|
||||
|
||||
void DutyUnit::loadState(const SaveState::SPU::Duty &dstate, const unsigned nr1, const unsigned nr4, const unsigned long cc) {
|
||||
nextPosUpdate = std::max(dstate.nextPosUpdate, cc);
|
||||
pos = dstate.pos & 7;
|
||||
setDuty(nr1);
|
||||
period = toPeriod((nr4 << 8 & 0x700) | dstate.nr3);
|
||||
enableEvents = true;
|
||||
setCounter();
|
||||
}
|
||||
|
||||
void DutyUnit::resetCounters(const unsigned long oldCc) {
|
||||
if (nextPosUpdate == COUNTER_DISABLED)
|
||||
return;
|
||||
|
||||
updatePos(oldCc);
|
||||
nextPosUpdate -= COUNTER_MAX;
|
||||
SoundUnit::resetCounters(oldCc);
|
||||
}
|
||||
|
||||
void DutyUnit::killCounter() {
|
||||
enableEvents = false;
|
||||
setCounter();
|
||||
}
|
||||
|
||||
void DutyUnit::reviveCounter(const unsigned long cc) {
|
||||
updatePos(cc);
|
||||
high = toOutState(duty, pos);
|
||||
enableEvents = true;
|
||||
setCounter();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aam�s *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef DUTY_UNIT_H
|
||||
#define DUTY_UNIT_H
|
||||
|
||||
#include "sound_unit.h"
|
||||
#include "master_disabler.h"
|
||||
#include "../savestate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class DutyUnit : public SoundUnit {
|
||||
unsigned long nextPosUpdate;
|
||||
unsigned short period;
|
||||
unsigned char pos;
|
||||
unsigned char duty;
|
||||
bool high;
|
||||
bool enableEvents;
|
||||
|
||||
void setCounter();
|
||||
void setDuty(unsigned nr1);
|
||||
void updatePos(unsigned long cc);
|
||||
|
||||
public:
|
||||
DutyUnit();
|
||||
void event();
|
||||
bool isHighState() const { return high; }
|
||||
void nr1Change(unsigned newNr1, unsigned long cc);
|
||||
void nr3Change(unsigned newNr3, unsigned long cc);
|
||||
void nr4Change(unsigned newNr4, unsigned long cc);
|
||||
void reset();
|
||||
void saveState(SaveState::SPU::Duty &dstate, unsigned long cc);
|
||||
void loadState(const SaveState::SPU::Duty &dstate, unsigned nr1, unsigned nr4, unsigned long cc);
|
||||
void resetCounters(unsigned long oldCc);
|
||||
void killCounter();
|
||||
void reviveCounter(unsigned long cc);
|
||||
|
||||
//intended for use by SweepUnit only.
|
||||
unsigned getFreq() const { return 2048 - (period >> 1); }
|
||||
void setFreq(unsigned newFreq, unsigned long cc);
|
||||
};
|
||||
|
||||
class DutyMasterDisabler : public MasterDisabler {
|
||||
DutyUnit &dutyUnit;
|
||||
public:
|
||||
DutyMasterDisabler(bool &m, DutyUnit &dutyUnit) : MasterDisabler(m), dutyUnit(dutyUnit) {}
|
||||
void operator()() { MasterDisabler::operator()(); dutyUnit.killCounter(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,106 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "envelope_unit.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
EnvelopeUnit::VolOnOffEvent EnvelopeUnit::nullEvent;
|
||||
|
||||
void EnvelopeUnit::event() {
|
||||
const unsigned long period = nr2 & 7;
|
||||
|
||||
if (period) {
|
||||
unsigned newVol = volume;
|
||||
|
||||
if (nr2 & 8)
|
||||
++newVol;
|
||||
else
|
||||
--newVol;
|
||||
|
||||
if (newVol < 0x10U) {
|
||||
volume = newVol;
|
||||
|
||||
if (volume < 2)
|
||||
volOnOffEvent(counter);
|
||||
|
||||
counter += period << 15;
|
||||
} else
|
||||
counter = COUNTER_DISABLED;
|
||||
} else
|
||||
counter += 8ul << 15;
|
||||
}
|
||||
|
||||
bool EnvelopeUnit::nr2Change(const unsigned newNr2) {
|
||||
if (!(nr2 & 7) && counter != COUNTER_DISABLED)
|
||||
++volume;
|
||||
else if (!(nr2 & 8))
|
||||
volume += 2;
|
||||
|
||||
if ((nr2 ^ newNr2) & 8)
|
||||
volume = 0x10 - volume;
|
||||
|
||||
volume &= 0xF;
|
||||
|
||||
nr2 = newNr2;
|
||||
|
||||
return !(newNr2 & 0xF8);
|
||||
}
|
||||
|
||||
bool EnvelopeUnit::nr4Init(const unsigned long cc) {
|
||||
{
|
||||
unsigned long period = nr2 & 7;
|
||||
|
||||
if (!period)
|
||||
period = 8;
|
||||
|
||||
if (!(cc & 0x7000))
|
||||
++period;
|
||||
|
||||
counter = cc - ((cc - 0x1000) & 0x7FFF) + period * 0x8000;
|
||||
}
|
||||
|
||||
volume = nr2 >> 4;
|
||||
|
||||
return !(nr2 & 0xF8);
|
||||
}
|
||||
|
||||
EnvelopeUnit::EnvelopeUnit(VolOnOffEvent &volOnOffEvent)
|
||||
: volOnOffEvent(volOnOffEvent),
|
||||
nr2(0),
|
||||
volume(0)
|
||||
{
|
||||
}
|
||||
|
||||
void EnvelopeUnit::reset() {
|
||||
counter = COUNTER_DISABLED;
|
||||
}
|
||||
|
||||
void EnvelopeUnit::saveState(SaveState::SPU::Env &estate) const {
|
||||
estate.counter = counter;
|
||||
estate.volume = volume;
|
||||
}
|
||||
|
||||
void EnvelopeUnit::loadState(const SaveState::SPU::Env &estate, const unsigned nr2, const unsigned long cc) {
|
||||
counter = std::max(estate.counter, cc);
|
||||
volume = estate.volume;
|
||||
this->nr2 = nr2;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef ENVELOPE_UNIT_H
|
||||
#define ENVELOPE_UNIT_H
|
||||
|
||||
#include "sound_unit.h"
|
||||
#include "../savestate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class EnvelopeUnit : public SoundUnit {
|
||||
public:
|
||||
struct VolOnOffEvent {
|
||||
virtual ~VolOnOffEvent() {}
|
||||
virtual void operator()(unsigned long /*cc*/) {}
|
||||
};
|
||||
|
||||
private:
|
||||
static VolOnOffEvent nullEvent;
|
||||
VolOnOffEvent &volOnOffEvent;
|
||||
unsigned char nr2;
|
||||
unsigned char volume;
|
||||
|
||||
public:
|
||||
explicit EnvelopeUnit(VolOnOffEvent &volOnOffEvent = nullEvent);
|
||||
void event();
|
||||
bool dacIsOn() const { return nr2 & 0xF8; }
|
||||
unsigned getVolume() const { return volume; }
|
||||
bool nr2Change(unsigned newNr2);
|
||||
bool nr4Init(unsigned long cycleCounter);
|
||||
void reset();
|
||||
void saveState(SaveState::SPU::Env &estate) const;
|
||||
void loadState(const SaveState::SPU::Env &estate, unsigned nr2, unsigned long cc);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,91 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "length_counter.h"
|
||||
#include "master_disabler.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
LengthCounter::LengthCounter(MasterDisabler &disabler, const unsigned mask) :
|
||||
disableMaster(disabler),
|
||||
lengthMask(mask)
|
||||
{
|
||||
init(false);
|
||||
nr1Change(0, 0, 0);
|
||||
}
|
||||
|
||||
void LengthCounter::event() {
|
||||
counter = COUNTER_DISABLED;
|
||||
lengthCounter = 0;
|
||||
disableMaster();
|
||||
}
|
||||
|
||||
void LengthCounter::nr1Change(const unsigned newNr1, const unsigned nr4, const unsigned long cycleCounter) {
|
||||
lengthCounter = (~newNr1 & lengthMask) + 1;
|
||||
counter = (nr4 & 0x40) ?( (cycleCounter >> 13) + lengthCounter) << 13 : static_cast<unsigned long>(COUNTER_DISABLED);
|
||||
}
|
||||
|
||||
void LengthCounter::nr4Change(const unsigned oldNr4, const unsigned newNr4, const unsigned long cycleCounter) {
|
||||
if (counter != COUNTER_DISABLED)
|
||||
lengthCounter = (counter >> 13) - (cycleCounter >> 13);
|
||||
|
||||
{
|
||||
unsigned dec = 0;
|
||||
|
||||
if (newNr4 & 0x40) {
|
||||
dec = ~cycleCounter >> 12 & 1;
|
||||
|
||||
if (!(oldNr4 & 0x40) && lengthCounter) {
|
||||
if (!(lengthCounter -= dec))
|
||||
disableMaster();
|
||||
}
|
||||
}
|
||||
|
||||
if ((newNr4 & 0x80) && !lengthCounter)
|
||||
lengthCounter = lengthMask + 1 - dec;
|
||||
}
|
||||
|
||||
if ((newNr4 & 0x40) && lengthCounter)
|
||||
counter = ((cycleCounter >> 13) + lengthCounter) << 13;
|
||||
else
|
||||
counter = COUNTER_DISABLED;
|
||||
}
|
||||
|
||||
/*void LengthCounter::reset() {
|
||||
counter = COUNTER_DISABLED;
|
||||
|
||||
if (cgb)
|
||||
lengthCounter = lengthMask + 1;
|
||||
}*/
|
||||
|
||||
void LengthCounter::init(const bool cgb) {
|
||||
this->cgb = cgb;
|
||||
}
|
||||
|
||||
void LengthCounter::saveState(SaveState::SPU::LCounter &lstate) const {
|
||||
lstate.counter = counter;
|
||||
lstate.lengthCounter = lengthCounter;
|
||||
}
|
||||
|
||||
void LengthCounter::loadState(const SaveState::SPU::LCounter &lstate, const unsigned long cc) {
|
||||
counter = std::max(lstate.counter, cc);
|
||||
lengthCounter = lstate.lengthCounter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef LENGTH_COUNTER_H
|
||||
#define LENGTH_COUNTER_H
|
||||
|
||||
#include "sound_unit.h"
|
||||
#include "../savestate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class MasterDisabler;
|
||||
|
||||
class LengthCounter : public SoundUnit {
|
||||
MasterDisabler &disableMaster;
|
||||
unsigned short lengthCounter;
|
||||
const unsigned char lengthMask;
|
||||
bool cgb;
|
||||
|
||||
public:
|
||||
LengthCounter(MasterDisabler &disabler, unsigned lengthMask);
|
||||
void event();
|
||||
void nr1Change(unsigned newNr1, unsigned nr4, unsigned long cc);
|
||||
void nr4Change(unsigned oldNr4, unsigned newNr4, unsigned long cc);
|
||||
// void reset();
|
||||
void init(bool cgb);
|
||||
void saveState(SaveState::SPU::LCounter &lstate) const;
|
||||
void loadState(const SaveState::SPU::LCounter &lstate, unsigned long cc);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef MASTER_DISABLER_H
|
||||
#define MASTER_DISABLER_H
|
||||
|
||||
namespace gambatte {
|
||||
class MasterDisabler {
|
||||
bool &master;
|
||||
|
||||
public:
|
||||
MasterDisabler(bool &m) : master(m) {}
|
||||
virtual ~MasterDisabler() {}
|
||||
virtual void operator()() { master = false; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SOUND_UNIT_H
|
||||
#define SOUND_UNIT_H
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class SoundUnit {
|
||||
protected:
|
||||
unsigned long counter;
|
||||
public:
|
||||
enum { COUNTER_MAX = 0x80000000u, COUNTER_DISABLED = 0xFFFFFFFFu };
|
||||
|
||||
SoundUnit() : counter(COUNTER_DISABLED) {}
|
||||
virtual ~SoundUnit() {}
|
||||
virtual void event() = 0;
|
||||
unsigned long getCounter() const { return counter; }
|
||||
virtual void resetCounters(unsigned long /*oldCc*/) { if (counter != COUNTER_DISABLED) counter -= COUNTER_MAX; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,45 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef STATIC_OUTPUT_TESTER_H
|
||||
#define STATIC_OUTPUT_TESTER_H
|
||||
|
||||
#include "envelope_unit.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
template<class Channel, class Unit>
|
||||
class StaticOutputTester : public EnvelopeUnit::VolOnOffEvent {
|
||||
const Channel &ch;
|
||||
Unit &unit;
|
||||
public:
|
||||
StaticOutputTester(const Channel &ch, Unit &unit) : ch(ch), unit(unit) {}
|
||||
void operator()(unsigned long cc);
|
||||
};
|
||||
|
||||
template<class Channel, class Unit>
|
||||
void StaticOutputTester<Channel, Unit>::operator()(const unsigned long cc) {
|
||||
if (ch.soMask && ch.master && ch.envelopeUnit.getVolume())
|
||||
unit.reviveCounter(cc);
|
||||
else
|
||||
unit.killCounter();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,183 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "state_osd_elements.h"
|
||||
#include "bitmap_font.h"
|
||||
#include "statesaver.h"
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace gambatte;
|
||||
using namespace bitmapfont;
|
||||
|
||||
static const char stateLoadedTxt[] = { S,t,a,t,e,SPC,N0,SPC,l,o,a,d,e,d,0 };
|
||||
static const char stateSavedTxt[] = { S,t,a,t,e,SPC,N0,SPC,s,a,v,e,d,0 };
|
||||
static const unsigned stateLoadedTxtWidth = getWidth(stateLoadedTxt);
|
||||
static const unsigned stateSavedTxtWidth = getWidth(stateSavedTxt);
|
||||
|
||||
class ShadedTextOsdElment : public OsdElement {
|
||||
struct ShadeFill {
|
||||
void operator()(uint_least32_t *dest, const unsigned pitch) const {
|
||||
dest[2] = dest[1] = dest[0] = 0x000000ul;
|
||||
dest += pitch;
|
||||
dest[2] = dest[0] = 0x000000ul;
|
||||
dest += pitch;
|
||||
dest[2] = dest[1] = dest[0] = 0x000000ul;
|
||||
}
|
||||
};
|
||||
|
||||
uint_least32_t *const pixels;
|
||||
unsigned life;
|
||||
|
||||
ShadedTextOsdElment(const ShadedTextOsdElment&);
|
||||
ShadedTextOsdElment& operator=(const ShadedTextOsdElment&);
|
||||
public:
|
||||
ShadedTextOsdElment(unsigned w, const char *txt);
|
||||
~ShadedTextOsdElment();
|
||||
const uint_least32_t* update();
|
||||
};
|
||||
|
||||
ShadedTextOsdElment::ShadedTextOsdElment(unsigned width, const char *txt) :
|
||||
OsdElement(MAX_WIDTH, 144 - HEIGHT - HEIGHT, width + 2, HEIGHT + 2, THREE_FOURTHS),
|
||||
pixels(new uint_least32_t[w() * h()]),
|
||||
life(4 * 60) {
|
||||
std::memset(pixels, 0xFF, w() * h() * sizeof(uint_least32_t));
|
||||
|
||||
/*print(pixels + 0 * w() + 0, w(), 0x000000ul, txt);
|
||||
print(pixels + 0 * w() + 1, w(), 0x000000ul, txt);
|
||||
print(pixels + 0 * w() + 2, w(), 0x000000ul, txt);
|
||||
print(pixels + 1 * w() + 0, w(), 0x000000ul, txt);
|
||||
print(pixels + 1 * w() + 2, w(), 0x000000ul, txt);
|
||||
print(pixels + 2 * w() + 0, w(), 0x000000ul, txt);
|
||||
print(pixels + 2 * w() + 1, w(), 0x000000ul, txt);
|
||||
print(pixels + 2 * w() + 2, w(), 0x000000ul, txt);
|
||||
print(pixels + 1 * w() + 1, w(), 0xE0E0E0ul, txt);*/
|
||||
|
||||
print(pixels, w(), ShadeFill(), txt);
|
||||
print(pixels + 1 * w() + 1, w(), 0xE0E0E0ul, txt);
|
||||
}
|
||||
|
||||
ShadedTextOsdElment::~ShadedTextOsdElment() {
|
||||
delete []pixels;
|
||||
}
|
||||
|
||||
const uint_least32_t* ShadedTextOsdElment::update() {
|
||||
if (life--)
|
||||
return pixels;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*class FramedTextOsdElment : public OsdElement {
|
||||
uint_least32_t *const pixels;
|
||||
unsigned life;
|
||||
|
||||
FramedTextOsdElment(const FramedTextOsdElment&);
|
||||
FramedTextOsdElment& operator=(const FramedTextOsdElment&);
|
||||
public:
|
||||
FramedTextOsdElment(unsigned w, const char *txt);
|
||||
~FramedTextOsdElment();
|
||||
const uint_least32_t* update();
|
||||
};
|
||||
|
||||
FramedTextOsdElment::FramedTextOsdElment(unsigned width, const char *txt) :
|
||||
OsdElement(NUMBER_WIDTH, 144 - HEIGHT * 2 - HEIGHT / 2, width + NUMBER_WIDTH * 2, HEIGHT * 2),
|
||||
pixels(new uint_least32_t[w() * h()]),
|
||||
life(4 * 60) {
|
||||
std::memset(pixels, 0x00, w() * h() * sizeof(uint_least32_t));
|
||||
print(pixels + (w() - width) / 2 + ((h() - HEIGHT) / 2) * w(), w(), 0xA0A0A0ul, txt);
|
||||
}
|
||||
|
||||
FramedTextOsdElment::~FramedTextOsdElment() {
|
||||
delete []pixels;
|
||||
}
|
||||
|
||||
const uint_least32_t* FramedTextOsdElment::update() {
|
||||
if (life--)
|
||||
return pixels;
|
||||
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
class SaveStateOsdElement : public OsdElement {
|
||||
uint_least32_t pixels[StateSaver::SS_WIDTH * StateSaver::SS_HEIGHT];
|
||||
unsigned life;
|
||||
|
||||
public:
|
||||
SaveStateOsdElement(const std::string &fileName, unsigned stateNo);
|
||||
const uint_least32_t* update();
|
||||
};
|
||||
|
||||
SaveStateOsdElement::SaveStateOsdElement(const std::string &fileName, unsigned stateNo) :
|
||||
OsdElement((stateNo ? stateNo - 1 : 9) * ((160 - StateSaver::SS_WIDTH) / 10)
|
||||
+ ((160 - StateSaver::SS_WIDTH) / 10) / 2, 4, StateSaver::SS_WIDTH, StateSaver::SS_HEIGHT),
|
||||
life(4 * 60) {
|
||||
std::ifstream file(fileName.c_str(), std::ios_base::binary);
|
||||
|
||||
if (file.is_open()) {
|
||||
file.ignore(5);
|
||||
file.read(reinterpret_cast<char*>(pixels), sizeof pixels);
|
||||
} else {
|
||||
std::memset(pixels, 0, sizeof pixels);
|
||||
|
||||
{
|
||||
using namespace bitmapfont;
|
||||
|
||||
static const char txt[] = { E,m,p,t,bitmapfont::y,0 };
|
||||
|
||||
print(pixels + 3 + (StateSaver::SS_HEIGHT / 2 - bitmapfont::HEIGHT / 2) * StateSaver::SS_WIDTH, StateSaver::SS_WIDTH, 0x808080ul, txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const uint_least32_t* SaveStateOsdElement::update() {
|
||||
if (life--)
|
||||
return pixels;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
std::auto_ptr<OsdElement> newStateLoadedOsdElement(unsigned stateNo) {
|
||||
char txt[sizeof stateLoadedTxt];
|
||||
|
||||
std::memcpy(txt, stateLoadedTxt, sizeof stateLoadedTxt);
|
||||
utoa(stateNo, txt + 6);
|
||||
|
||||
return std::auto_ptr<OsdElement>(new ShadedTextOsdElment(stateLoadedTxtWidth, txt));
|
||||
}
|
||||
|
||||
std::auto_ptr<OsdElement> newStateSavedOsdElement(unsigned stateNo) {
|
||||
char txt[sizeof stateSavedTxt];
|
||||
|
||||
std::memcpy(txt, stateSavedTxt, sizeof stateSavedTxt);
|
||||
utoa(stateNo, txt + 6);
|
||||
|
||||
return std::auto_ptr<OsdElement>(new ShadedTextOsdElment(stateSavedTxtWidth, txt));
|
||||
}
|
||||
|
||||
std::auto_ptr<OsdElement> newSaveStateOsdElement(const std::string &fileName, unsigned stateNo) {
|
||||
return std::auto_ptr<OsdElement>(new SaveStateOsdElement(fileName, stateNo));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef STATE_OSD_ELEMENTS_H
|
||||
#define STATE_OSD_ELEMENTS_H
|
||||
|
||||
#include "osd_element.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace gambatte {
|
||||
std::auto_ptr<OsdElement> newStateLoadedOsdElement(unsigned stateNo);
|
||||
std::auto_ptr<OsdElement> newStateSavedOsdElement(unsigned stateNo);
|
||||
std::auto_ptr<OsdElement> newSaveStateOsdElement(const std::string &fileName, unsigned stateNo);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,524 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "statesaver.h"
|
||||
#include "savestate.h"
|
||||
#include "array.h"
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
class omemstream
|
||||
{
|
||||
public:
|
||||
omemstream(void *data) : wr_ptr(static_cast<uint8_t*>(data)), has_written(0) {}
|
||||
|
||||
void put(uint8_t data)
|
||||
{
|
||||
if (wr_ptr)
|
||||
*wr_ptr++ = data;
|
||||
has_written++;
|
||||
}
|
||||
|
||||
void write(const void *data, size_t size)
|
||||
{
|
||||
if (wr_ptr)
|
||||
{
|
||||
std::memcpy(wr_ptr, data, size);
|
||||
wr_ptr += size;
|
||||
}
|
||||
|
||||
has_written += size;
|
||||
}
|
||||
|
||||
size_t size() const { return has_written; }
|
||||
bool fail() const { return false; }
|
||||
bool good() const { return true; }
|
||||
|
||||
private:
|
||||
uint8_t *wr_ptr;
|
||||
size_t has_written;
|
||||
};
|
||||
|
||||
class imemstream
|
||||
{
|
||||
public:
|
||||
imemstream(const void *data) : rd_ptr(static_cast<const uint8_t*>(data)), has_read(0) {}
|
||||
|
||||
uint8_t get()
|
||||
{
|
||||
uint8_t ret = *rd_ptr++;
|
||||
has_read++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void read(void *data, size_t size)
|
||||
{
|
||||
std::memcpy(data, rd_ptr, size);
|
||||
rd_ptr += size;
|
||||
}
|
||||
|
||||
void ignore(size_t len = 1)
|
||||
{
|
||||
rd_ptr += len;
|
||||
has_read += len;
|
||||
}
|
||||
|
||||
void getline(char *data, size_t size, char delim = '\n')
|
||||
{
|
||||
size_t count = 0;
|
||||
while ((count < size - 1) && (*rd_ptr != delim))
|
||||
{
|
||||
*data++ = *rd_ptr++;
|
||||
has_read++;
|
||||
}
|
||||
|
||||
rd_ptr++;
|
||||
has_read++;
|
||||
*data = '\0';
|
||||
}
|
||||
|
||||
bool fail() const { return false; }
|
||||
bool good() const { return true; }
|
||||
|
||||
private:
|
||||
const uint8_t *rd_ptr;
|
||||
size_t has_read;
|
||||
};
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace gambatte;
|
||||
|
||||
enum AsciiChar {
|
||||
NUL, SOH, STX, ETX, EOT, ENQ, ACK, BEL, BS, TAB, LF, VT, FF, CR, SO, SI,
|
||||
DLE, DC1, DC2, DC3, DC4, NAK, SYN, ETB, CAN, EM, SUB, ESC, FS, GS, RS, US,
|
||||
SP, XCL, QOT, HSH, DLR, PRC, AMP, APO, LPA, RPA, AST, PLU, COM, HYP, STP, DIV,
|
||||
NO0, NO1, NO2, NO3, NO4, NO5, NO6, NO7, NO8, NO9, CLN, SCL, LT, EQL, GT, QTN,
|
||||
AT, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
|
||||
P, Q, R, S, T, U, V, W, X, Y, Z, LBX, BSL, RBX, CAT, UND,
|
||||
ACN, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o,
|
||||
p, q, r, s, t, u, v, w, x, y, z, LBR, BAR, RBR, TLD, DEL
|
||||
};
|
||||
|
||||
struct Saver {
|
||||
const char *label;
|
||||
void (*save)(omemstream &file, const SaveState &state);
|
||||
void (*load)(imemstream &file, SaveState &state);
|
||||
unsigned char labelsize;
|
||||
};
|
||||
|
||||
static inline bool operator<(const Saver &l, const Saver &r) {
|
||||
return std::strcmp(l.label, r.label) < 0;
|
||||
}
|
||||
|
||||
static void put24(omemstream &file, const unsigned long data) {
|
||||
file.put(data >> 16 & 0xFF);
|
||||
file.put(data >> 8 & 0xFF);
|
||||
file.put(data & 0xFF);
|
||||
}
|
||||
|
||||
static void put32(omemstream &file, const unsigned long data) {
|
||||
file.put(data >> 24 & 0xFF);
|
||||
file.put(data >> 16 & 0xFF);
|
||||
file.put(data >> 8 & 0xFF);
|
||||
file.put(data & 0xFF);
|
||||
}
|
||||
|
||||
static void write(omemstream &file, const unsigned char data) {
|
||||
static const char inf[] = { 0x00, 0x00, 0x01 };
|
||||
|
||||
file.write(inf, sizeof(inf));
|
||||
file.put(data & 0xFF);
|
||||
}
|
||||
|
||||
static void write(omemstream &file, const unsigned short data) {
|
||||
static const char inf[] = { 0x00, 0x00, 0x02 };
|
||||
|
||||
file.write(inf, sizeof(inf));
|
||||
file.put(data >> 8 & 0xFF);
|
||||
file.put(data & 0xFF);
|
||||
}
|
||||
|
||||
static void write(omemstream &file, const unsigned long data) {
|
||||
static const char inf[] = { 0x00, 0x00, 0x04 };
|
||||
|
||||
file.write(inf, sizeof(inf));
|
||||
put32(file, data);
|
||||
}
|
||||
|
||||
static inline void write(omemstream &file, const bool data) {
|
||||
write(file, static_cast<unsigned char>(data));
|
||||
}
|
||||
|
||||
static void write(omemstream &file, const unsigned char *data, const unsigned long sz) {
|
||||
put24(file, sz);
|
||||
file.write(reinterpret_cast<const char*>(data), sz);
|
||||
}
|
||||
|
||||
static void write(omemstream &file, const bool *data, const unsigned long sz) {
|
||||
put24(file, sz);
|
||||
|
||||
for (unsigned long i = 0; i < sz; ++i)
|
||||
file.put(data[i]);
|
||||
}
|
||||
|
||||
static unsigned long get24(imemstream &file) {
|
||||
unsigned long tmp = file.get() & 0xFF;
|
||||
|
||||
tmp = tmp << 8 | (file.get() & 0xFF);
|
||||
|
||||
return tmp << 8 | (file.get() & 0xFF);
|
||||
}
|
||||
|
||||
static unsigned long read(imemstream &file) {
|
||||
unsigned long size = get24(file);
|
||||
|
||||
if (size > 4) {
|
||||
file.ignore(size - 4);
|
||||
size = 4;
|
||||
}
|
||||
|
||||
unsigned long out = 0;
|
||||
|
||||
switch (size) {
|
||||
case 4: out = (out | (file.get() & 0xFF)) << 8;
|
||||
case 3: out = (out | (file.get() & 0xFF)) << 8;
|
||||
case 2: out = (out | (file.get() & 0xFF)) << 8;
|
||||
case 1: out = out | (file.get() & 0xFF);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline void read(imemstream &file, unsigned char &data) {
|
||||
data = read(file) & 0xFF;
|
||||
}
|
||||
|
||||
static inline void read(imemstream &file, unsigned short &data) {
|
||||
data = read(file) & 0xFFFF;
|
||||
}
|
||||
|
||||
static inline void read(imemstream &file, unsigned long &data) {
|
||||
data = read(file);
|
||||
}
|
||||
|
||||
static inline void read(imemstream &file, bool &data) {
|
||||
data = read(file);
|
||||
}
|
||||
|
||||
static void read(imemstream &file, unsigned char *data, unsigned long sz) {
|
||||
const unsigned long size = get24(file);
|
||||
|
||||
if (size < sz)
|
||||
sz = size;
|
||||
|
||||
file.read(reinterpret_cast<char*>(data), sz);
|
||||
file.ignore(size - sz);
|
||||
|
||||
if (static_cast<unsigned char>(0x100)) {
|
||||
for (unsigned long i = 0; i < sz; ++i)
|
||||
data[i] &= 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
static void read(imemstream &file, bool *data, unsigned long sz) {
|
||||
const unsigned long size = get24(file);
|
||||
|
||||
if (size < sz)
|
||||
sz = size;
|
||||
|
||||
for (unsigned long i = 0; i < sz; ++i)
|
||||
data[i] = file.get();
|
||||
|
||||
file.ignore(size - sz);
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class SaverList {
|
||||
public:
|
||||
typedef std::vector<Saver> list_t;
|
||||
typedef list_t::const_iterator const_iterator;
|
||||
|
||||
private:
|
||||
list_t list;
|
||||
unsigned char maxLabelsize_;
|
||||
|
||||
public:
|
||||
SaverList();
|
||||
const_iterator begin() const { return list.begin(); }
|
||||
const_iterator end() const { return list.end(); }
|
||||
unsigned maxLabelsize() const { return maxLabelsize_; }
|
||||
};
|
||||
|
||||
static void pushSaver(SaverList::list_t &list, const char *label,
|
||||
void (*save)(omemstream &file, const SaveState &state),
|
||||
void (*load)(imemstream &file, SaveState &state), unsigned labelsize) {
|
||||
const Saver saver = { label, save, load, labelsize };
|
||||
list.push_back(saver);
|
||||
}
|
||||
|
||||
SaverList::SaverList() {
|
||||
#define ADD(arg) do { \
|
||||
struct Func { \
|
||||
static void save(omemstream &file, const SaveState &state) { write(file, state.arg); } \
|
||||
static void load(imemstream &file, SaveState &state) { read(file, state.arg); } \
|
||||
}; \
|
||||
\
|
||||
pushSaver(list, label, Func::save, Func::load, sizeof label); \
|
||||
} while (0)
|
||||
|
||||
#define ADDPTR(arg) do { \
|
||||
struct Func { \
|
||||
static void save(omemstream &file, const SaveState &state) { write(file, state.arg.get(), state.arg.getSz()); } \
|
||||
static void load(imemstream &file, SaveState &state) { read(file, state.arg.ptr, state.arg.getSz()); } \
|
||||
}; \
|
||||
\
|
||||
pushSaver(list, label, Func::save, Func::load, sizeof label); \
|
||||
} while (0)
|
||||
|
||||
#define ADDARRAY(arg) do { \
|
||||
struct Func { \
|
||||
static void save(omemstream &file, const SaveState &state) { write(file, state.arg, sizeof(state.arg)); } \
|
||||
static void load(imemstream &file, SaveState &state) { read(file, state.arg, sizeof(state.arg)); } \
|
||||
}; \
|
||||
\
|
||||
pushSaver(list, label, Func::save, Func::load, sizeof label); \
|
||||
} while (0)
|
||||
|
||||
{ static const char label[] = { c,c, NUL }; ADD(cpu.cycleCounter); }
|
||||
{ static const char label[] = { p,c, NUL }; ADD(cpu.PC); }
|
||||
{ static const char label[] = { s,p, NUL }; ADD(cpu.SP); }
|
||||
{ static const char label[] = { a, NUL }; ADD(cpu.A); }
|
||||
{ static const char label[] = { b, NUL }; ADD(cpu.B); }
|
||||
{ static const char label[] = { c, NUL }; ADD(cpu.C); }
|
||||
{ static const char label[] = { d, NUL }; ADD(cpu.D); }
|
||||
{ static const char label[] = { e, NUL }; ADD(cpu.E); }
|
||||
{ static const char label[] = { f, NUL }; ADD(cpu.F); }
|
||||
{ static const char label[] = { h, NUL }; ADD(cpu.H); }
|
||||
{ static const char label[] = { l, NUL }; ADD(cpu.L); }
|
||||
{ static const char label[] = { s,k,i,p, NUL }; ADD(cpu.skip); }
|
||||
{ static const char label[] = { h,a,l,t, NUL }; ADD(mem.halted); }
|
||||
{ static const char label[] = { v,r,a,m, NUL }; ADDPTR(mem.vram); }
|
||||
{ static const char label[] = { s,r,a,m, NUL }; ADDPTR(mem.sram); }
|
||||
{ static const char label[] = { w,r,a,m, NUL }; ADDPTR(mem.wram); }
|
||||
{ static const char label[] = { h,r,a,m, NUL }; ADDPTR(mem.ioamhram); }
|
||||
{ static const char label[] = { l,d,i,v,u,p, NUL }; ADD(mem.divLastUpdate); }
|
||||
{ static const char label[] = { l,t,i,m,a,u,p, NUL }; ADD(mem.timaLastUpdate); }
|
||||
{ static const char label[] = { t,m,a,t,i,m,e, NUL }; ADD(mem.tmatime); }
|
||||
{ static const char label[] = { s,e,r,i,a,l,t, NUL }; ADD(mem.nextSerialtime); }
|
||||
{ static const char label[] = { l,o,d,m,a,u,p, NUL }; ADD(mem.lastOamDmaUpdate); }
|
||||
{ static const char label[] = { m,i,n,i,n,t,t, NUL }; ADD(mem.minIntTime); }
|
||||
{ static const char label[] = { u,n,h,a,l,t,t, NUL }; ADD(mem.unhaltTime); }
|
||||
{ static const char label[] = { r,o,m,b,a,n,k, NUL }; ADD(mem.rombank); }
|
||||
{ static const char label[] = { d,m,a,s,r,c, NUL }; ADD(mem.dmaSource); }
|
||||
{ static const char label[] = { d,m,a,d,s,t, NUL }; ADD(mem.dmaDestination); }
|
||||
{ static const char label[] = { r,a,m,b,a,n,k, NUL }; ADD(mem.rambank); }
|
||||
{ static const char label[] = { o,d,m,a,p,o,s, NUL }; ADD(mem.oamDmaPos); }
|
||||
{ static const char label[] = { i,m,e, NUL }; ADD(mem.IME); }
|
||||
{ static const char label[] = { s,r,a,m,o,n, NUL }; ADD(mem.enableRam); }
|
||||
{ static const char label[] = { r,a,m,b,m,o,d, NUL }; ADD(mem.rambankMode); }
|
||||
{ static const char label[] = { h,d,m,a, NUL }; ADD(mem.hdmaTransfer); }
|
||||
{ static const char label[] = { b,g,p, NUL }; ADDPTR(ppu.bgpData); }
|
||||
{ static const char label[] = { o,b,j,p, NUL }; ADDPTR(ppu.objpData); }
|
||||
{ static const char label[] = { s,p,o,s,b,u,f, NUL }; ADDPTR(ppu.oamReaderBuf); }
|
||||
{ static const char label[] = { s,p,s,z,b,u,f, NUL }; ADDPTR(ppu.oamReaderSzbuf); }
|
||||
{ static const char label[] = { s,p,a,t,t,r, NUL }; ADDARRAY(ppu.spAttribList); }
|
||||
{ static const char label[] = { s,p,b,y,t,e,NO0, NUL }; ADDARRAY(ppu.spByte0List); }
|
||||
{ static const char label[] = { s,p,b,y,t,e,NO1, NUL }; ADDARRAY(ppu.spByte1List); }
|
||||
{ static const char label[] = { v,c,y,c,l,e,s, NUL }; ADD(ppu.videoCycles); }
|
||||
{ static const char label[] = { e,d,M,NO0,t,i,m, NUL }; ADD(ppu.enableDisplayM0Time); }
|
||||
{ static const char label[] = { m,NO0,t,i,m,e, NUL }; ADD(ppu.lastM0Time); }
|
||||
{ static const char label[] = { n,m,NO0,i,r,q, NUL }; ADD(ppu.nextM0Irq); }
|
||||
{ static const char label[] = { b,g,t,w, NUL }; ADD(ppu.tileword); }
|
||||
{ static const char label[] = { b,g,n,t,w, NUL }; ADD(ppu.ntileword); }
|
||||
{ static const char label[] = { w,i,n,y,p,o,s, NUL }; ADD(ppu.winYPos); }
|
||||
{ static const char label[] = { x,p,o,s, NUL }; ADD(ppu.xpos); }
|
||||
{ static const char label[] = { e,n,d,x, NUL }; ADD(ppu.endx); }
|
||||
{ static const char label[] = { p,p,u,r,NO0, NUL }; ADD(ppu.reg0); }
|
||||
{ static const char label[] = { p,p,u,r,NO1, NUL }; ADD(ppu.reg1); }
|
||||
{ static const char label[] = { b,g,a,t,r,b, NUL }; ADD(ppu.attrib); }
|
||||
{ static const char label[] = { b,g,n,a,t,r,b, NUL }; ADD(ppu.nattrib); }
|
||||
{ static const char label[] = { p,p,u,s,t,a,t, NUL }; ADD(ppu.state); }
|
||||
{ static const char label[] = { n,s,p,r,i,t,e, NUL }; ADD(ppu.nextSprite); }
|
||||
{ static const char label[] = { c,s,p,r,i,t,e, NUL }; ADD(ppu.currentSprite); }
|
||||
{ static const char label[] = { l,y,c, NUL }; ADD(ppu.lyc); }
|
||||
{ static const char label[] = { m,NO0,l,y,c, NUL }; ADD(ppu.m0lyc); }
|
||||
{ static const char label[] = { o,l,d,w,y, NUL }; ADD(ppu.oldWy); }
|
||||
{ static const char label[] = { w,i,n,d,r,a,w, NUL }; ADD(ppu.winDrawState); }
|
||||
{ static const char label[] = { w,s,c,x, NUL }; ADD(ppu.wscx); }
|
||||
{ static const char label[] = { w,e,m,a,s,t,r, NUL }; ADD(ppu.weMaster); }
|
||||
{ static const char label[] = { l,c,d,s,i,r,q, NUL }; ADD(ppu.pendingLcdstatIrq); }
|
||||
{ static const char label[] = { s,p,u,c,n,t,r, NUL }; ADD(spu.cycleCounter); }
|
||||
{ static const char label[] = { s,w,p,c,n,t,r, NUL }; ADD(spu.ch1.sweep.counter); }
|
||||
{ static const char label[] = { s,w,p,s,h,d,w, NUL }; ADD(spu.ch1.sweep.shadow); }
|
||||
{ static const char label[] = { s,w,p,n,e,g, NUL }; ADD(spu.ch1.sweep.negging); }
|
||||
{ static const char label[] = { d,u,t,NO1,c,t,r, NUL }; ADD(spu.ch1.duty.nextPosUpdate); }
|
||||
{ static const char label[] = { d,u,t,NO1,p,o,s, NUL }; ADD(spu.ch1.duty.pos); }
|
||||
{ static const char label[] = { e,n,v,NO1,c,t,r, NUL }; ADD(spu.ch1.env.counter); }
|
||||
{ static const char label[] = { e,n,v,NO1,v,o,l, NUL }; ADD(spu.ch1.env.volume); }
|
||||
{ static const char label[] = { l,e,n,NO1,c,t,r, NUL }; ADD(spu.ch1.lcounter.counter); }
|
||||
{ static const char label[] = { l,e,n,NO1,v,a,l, NUL }; ADD(spu.ch1.lcounter.lengthCounter); }
|
||||
{ static const char label[] = { n,r,NO1,NO0, NUL }; ADD(spu.ch1.sweep.nr0); }
|
||||
{ static const char label[] = { n,r,NO1,NO3, NUL }; ADD(spu.ch1.duty.nr3); }
|
||||
{ static const char label[] = { n,r,NO1,NO4, NUL }; ADD(spu.ch1.nr4); }
|
||||
{ static const char label[] = { c,NO1,m,a,s,t,r, NUL }; ADD(spu.ch1.master); }
|
||||
{ static const char label[] = { d,u,t,NO2,c,t,r, NUL }; ADD(spu.ch2.duty.nextPosUpdate); }
|
||||
{ static const char label[] = { d,u,t,NO2,p,o,s, NUL }; ADD(spu.ch2.duty.pos); }
|
||||
{ static const char label[] = { e,n,v,NO2,c,t,r, NUL }; ADD(spu.ch2.env.counter); }
|
||||
{ static const char label[] = { e,n,v,NO2,v,o,l, NUL }; ADD(spu.ch2.env.volume); }
|
||||
{ static const char label[] = { l,e,n,NO2,c,t,r, NUL }; ADD(spu.ch2.lcounter.counter); }
|
||||
{ static const char label[] = { l,e,n,NO2,v,a,l, NUL }; ADD(spu.ch2.lcounter.lengthCounter); }
|
||||
{ static const char label[] = { n,r,NO2,NO3, NUL }; ADD(spu.ch2.duty.nr3); }
|
||||
{ static const char label[] = { n,r,NO2,NO4, NUL }; ADD(spu.ch2.nr4); }
|
||||
{ static const char label[] = { c,NO2,m,a,s,t,r, NUL }; ADD(spu.ch2.master); }
|
||||
{ static const char label[] = { w,a,v,e,r,a,m, NUL }; ADDPTR(spu.ch3.waveRam); }
|
||||
{ static const char label[] = { l,e,n,NO3,c,t,r, NUL }; ADD(spu.ch3.lcounter.counter); }
|
||||
{ static const char label[] = { l,e,n,NO3,v,a,l, NUL }; ADD(spu.ch3.lcounter.lengthCounter); }
|
||||
{ static const char label[] = { w,a,v,e,c,t,r, NUL }; ADD(spu.ch3.waveCounter); }
|
||||
{ static const char label[] = { l,w,a,v,r,d,t, NUL }; ADD(spu.ch3.lastReadTime); }
|
||||
{ static const char label[] = { w,a,v,e,p,o,s, NUL }; ADD(spu.ch3.wavePos); }
|
||||
{ static const char label[] = { w,a,v,s,m,p,l, NUL }; ADD(spu.ch3.sampleBuf); }
|
||||
{ static const char label[] = { n,r,NO3,NO3, NUL }; ADD(spu.ch3.nr3); }
|
||||
{ static const char label[] = { n,r,NO3,NO4, NUL }; ADD(spu.ch3.nr4); }
|
||||
{ static const char label[] = { c,NO3,m,a,s,t,r, NUL }; ADD(spu.ch3.master); }
|
||||
{ static const char label[] = { l,f,s,r,c,t,r, NUL }; ADD(spu.ch4.lfsr.counter); }
|
||||
{ static const char label[] = { l,f,s,r,r,e,g, NUL }; ADD(spu.ch4.lfsr.reg); }
|
||||
{ static const char label[] = { e,n,v,NO4,c,t,r, NUL }; ADD(spu.ch4.env.counter); }
|
||||
{ static const char label[] = { e,n,v,NO4,v,o,l, NUL }; ADD(spu.ch4.env.volume); }
|
||||
{ static const char label[] = { l,e,n,NO4,c,t,r, NUL }; ADD(spu.ch4.lcounter.counter); }
|
||||
{ static const char label[] = { l,e,n,NO4,v,a,l, NUL }; ADD(spu.ch4.lcounter.lengthCounter); }
|
||||
{ static const char label[] = { n,r,NO4,NO4, NUL }; ADD(spu.ch4.nr4); }
|
||||
{ static const char label[] = { c,NO4,m,a,s,t,r, NUL }; ADD(spu.ch4.master); }
|
||||
{ static const char label[] = { r,t,c,b,a,s,e, NUL }; ADD(rtc.baseTime); }
|
||||
{ static const char label[] = { r,t,c,h,a,l,t, NUL }; ADD(rtc.haltTime); }
|
||||
//{ static const char label[] = { r,t,c,i,n,d,x, NUL }; ADD(rtc.index); }
|
||||
{ static const char label[] = { r,t,c,d,h, NUL }; ADD(rtc.dataDh); }
|
||||
{ static const char label[] = { r,t,c,d,l, NUL }; ADD(rtc.dataDl); }
|
||||
{ static const char label[] = { r,t,c,h, NUL }; ADD(rtc.dataH); }
|
||||
{ static const char label[] = { r,t,c,m, NUL }; ADD(rtc.dataM); }
|
||||
{ static const char label[] = { r,t,c,s, NUL }; ADD(rtc.dataS); }
|
||||
{ static const char label[] = { r,t,c,l,l,d, NUL }; ADD(rtc.lastLatchData); }
|
||||
|
||||
#undef ADD
|
||||
#undef ADDPTR
|
||||
#undef ADDARRAY
|
||||
|
||||
list.resize(list.size());
|
||||
std::sort(list.begin(), list.end());
|
||||
|
||||
maxLabelsize_ = 0;
|
||||
|
||||
for (std::size_t i = 0; i < list.size(); ++i) {
|
||||
if (list[i].labelsize > maxLabelsize_)
|
||||
maxLabelsize_ = list[i].labelsize;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
static void writeSnapShot(omemstream &file) {
|
||||
put24(file, 0);
|
||||
}
|
||||
|
||||
static SaverList list;
|
||||
|
||||
} // anon namespace
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
void StateSaver::saveState(const SaveState &state, void *data) {
|
||||
omemstream file(data);
|
||||
|
||||
if (file.fail())
|
||||
return;
|
||||
|
||||
{ static const char ver[] = { 0, 1 }; file.write(ver, sizeof(ver)); }
|
||||
|
||||
writeSnapShot(file);
|
||||
|
||||
for (SaverList::const_iterator it = list.begin(); it != list.end(); ++it) {
|
||||
file.write(it->label, it->labelsize);
|
||||
(*it->save)(file, state);
|
||||
}
|
||||
}
|
||||
|
||||
bool StateSaver::loadState(SaveState &state, const void *data) {
|
||||
imemstream file(data);
|
||||
|
||||
if (file.fail() || file.get() != 0)
|
||||
return false;
|
||||
|
||||
file.ignore();
|
||||
file.ignore(get24(file));
|
||||
|
||||
const Array<char> labelbuf(list.maxLabelsize());
|
||||
const Saver labelbufSaver = { labelbuf, 0, 0, list.maxLabelsize() };
|
||||
|
||||
SaverList::const_iterator done = list.begin();
|
||||
|
||||
while (file.good() && done != list.end()) {
|
||||
file.getline(labelbuf, list.maxLabelsize(), NUL);
|
||||
|
||||
SaverList::const_iterator it = done;
|
||||
|
||||
if (std::strcmp(labelbuf, it->label)) {
|
||||
it = std::lower_bound(it + 1, list.end(), labelbufSaver);
|
||||
|
||||
if (it == list.end() || std::strcmp(labelbuf, it->label)) {
|
||||
file.ignore(get24(file));
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
++done;
|
||||
|
||||
(*it->load)(file, state);
|
||||
}
|
||||
|
||||
state.cpu.cycleCounter &= 0x7FFFFFFF;
|
||||
state.spu.cycleCounter &= 0x7FFFFFFF;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t StateSaver::stateSize(const SaveState &state) {
|
||||
omemstream file(0);
|
||||
|
||||
if (file.fail())
|
||||
return 0;
|
||||
|
||||
{ static const char ver[] = { 0, 1 }; file.write(ver, sizeof(ver)); }
|
||||
|
||||
writeSnapShot(file);
|
||||
|
||||
for (SaverList::const_iterator it = list.begin(); it != list.end(); ++it) {
|
||||
file.write(it->label, it->labelsize);
|
||||
(*it->save)(file, state);
|
||||
}
|
||||
|
||||
return file.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef STATESAVER_H
|
||||
#define STATESAVER_H
|
||||
|
||||
#include "gbint.h"
|
||||
#include <string>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
struct SaveState;
|
||||
|
||||
class StateSaver {
|
||||
StateSaver();
|
||||
|
||||
public:
|
||||
enum { SS_SHIFT = 2 };
|
||||
enum { SS_DIV = 1 << 2 };
|
||||
enum { SS_WIDTH = 160 >> SS_SHIFT };
|
||||
enum { SS_HEIGHT = 144 >> SS_SHIFT };
|
||||
|
||||
//static bool saveState(const SaveState &state,
|
||||
// const uint_least32_t *videoBuf, int pitch, const std::string &filename);
|
||||
//static bool loadState(SaveState &state, const std::string &filename);
|
||||
static void saveState(const SaveState &state, void *data);
|
||||
static bool loadState(SaveState &state, const void *data);
|
||||
static size_t stateSize(const SaveState &state);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,171 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "tima.h"
|
||||
#include "savestate.h"
|
||||
|
||||
static const unsigned char timaClock[4] = { 10, 4, 6, 8 };
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
Tima::Tima() :
|
||||
lastUpdate_(0),
|
||||
tmatime_(DISABLED_TIME),
|
||||
tima_(0),
|
||||
tma_(0),
|
||||
tac_(0)
|
||||
{}
|
||||
|
||||
void Tima::saveState(SaveState &state) const {
|
||||
state.mem.timaLastUpdate = lastUpdate_;
|
||||
state.mem.tmatime = tmatime_;
|
||||
}
|
||||
|
||||
void Tima::loadState(const SaveState &state, const TimaInterruptRequester timaIrq) {
|
||||
lastUpdate_ = state.mem.timaLastUpdate;
|
||||
tmatime_ = state.mem.tmatime;
|
||||
|
||||
tima_ = state.mem.ioamhram.get()[0x105];
|
||||
tma_ = state.mem.ioamhram.get()[0x106];
|
||||
tac_ = state.mem.ioamhram.get()[0x107];
|
||||
|
||||
timaIrq.setNextIrqEventTime((tac_ & 4)
|
||||
?
|
||||
(tmatime_ != DISABLED_TIME && tmatime_ > state.cpu.cycleCounter
|
||||
? tmatime_
|
||||
: lastUpdate_ + ((256u - tima_) << timaClock[tac_ & 3]) + 3)
|
||||
:
|
||||
static_cast<unsigned long>(DISABLED_TIME)
|
||||
);
|
||||
}
|
||||
|
||||
void Tima::resetCc(const unsigned long oldCc, const unsigned long newCc, const TimaInterruptRequester timaIrq) {
|
||||
const unsigned long dec = oldCc - newCc;
|
||||
|
||||
if (tac_ & 0x04) {
|
||||
updateIrq(oldCc, timaIrq);
|
||||
updateTima(oldCc);
|
||||
|
||||
lastUpdate_ -= dec;
|
||||
timaIrq.setNextIrqEventTime(timaIrq.nextIrqEventTime() - dec);
|
||||
|
||||
if (tmatime_ != DISABLED_TIME)
|
||||
tmatime_ -= dec;
|
||||
}
|
||||
}
|
||||
|
||||
void Tima::updateTima(const unsigned long cycleCounter) {
|
||||
const unsigned long ticks = (cycleCounter - lastUpdate_) >> timaClock[tac_ & 3];
|
||||
|
||||
lastUpdate_ += ticks << timaClock[tac_ & 3];
|
||||
|
||||
if (cycleCounter >= tmatime_) {
|
||||
if (cycleCounter >= tmatime_ + 4)
|
||||
tmatime_ = DISABLED_TIME;
|
||||
|
||||
tima_ = tma_;
|
||||
}
|
||||
|
||||
unsigned long tmp = tima_ + ticks;
|
||||
|
||||
while (tmp > 0x100)
|
||||
tmp -= 0x100 - tma_;
|
||||
|
||||
if (tmp == 0x100) {
|
||||
tmp = 0;
|
||||
tmatime_ = lastUpdate_ + 3;
|
||||
|
||||
if (cycleCounter >= tmatime_) {
|
||||
if (cycleCounter >= tmatime_ + 4)
|
||||
tmatime_ = DISABLED_TIME;
|
||||
|
||||
tmp = tma_;
|
||||
}
|
||||
}
|
||||
|
||||
tima_ = tmp;
|
||||
}
|
||||
|
||||
void Tima::setTima(const unsigned data, const unsigned long cycleCounter, const TimaInterruptRequester timaIrq) {
|
||||
if (tac_ & 0x04) {
|
||||
updateIrq(cycleCounter, timaIrq);
|
||||
updateTima(cycleCounter);
|
||||
|
||||
if (tmatime_ - cycleCounter < 4)
|
||||
tmatime_ = DISABLED_TIME;
|
||||
|
||||
timaIrq.setNextIrqEventTime(lastUpdate_ + ((256u - data) << timaClock[tac_ & 3]) + 3);
|
||||
}
|
||||
|
||||
tima_ = data;
|
||||
}
|
||||
|
||||
void Tima::setTma(const unsigned data, const unsigned long cycleCounter, const TimaInterruptRequester timaIrq) {
|
||||
if (tac_ & 0x04) {
|
||||
updateIrq(cycleCounter, timaIrq);
|
||||
updateTima(cycleCounter);
|
||||
}
|
||||
|
||||
tma_ = data;
|
||||
}
|
||||
|
||||
void Tima::setTac(const unsigned data, const unsigned long cycleCounter, const TimaInterruptRequester timaIrq) {
|
||||
if (tac_ ^ data) {
|
||||
unsigned long nextIrqEventTime = timaIrq.nextIrqEventTime();
|
||||
|
||||
if (tac_ & 0x04) {
|
||||
updateIrq(cycleCounter, timaIrq);
|
||||
updateTima(cycleCounter);
|
||||
|
||||
lastUpdate_ -= (1u << (timaClock[tac_ & 3] - 1)) + 3;
|
||||
tmatime_ -= (1u << (timaClock[tac_ & 3] - 1)) + 3;
|
||||
nextIrqEventTime -= (1u << (timaClock[tac_ & 3] - 1)) + 3;
|
||||
|
||||
if (cycleCounter >= nextIrqEventTime)
|
||||
timaIrq.flagIrq();
|
||||
|
||||
updateTima(cycleCounter);
|
||||
|
||||
tmatime_ = DISABLED_TIME;
|
||||
nextIrqEventTime = DISABLED_TIME;
|
||||
}
|
||||
|
||||
if (data & 4) {
|
||||
lastUpdate_ = (cycleCounter >> timaClock[data & 3]) << timaClock[data & 3];
|
||||
nextIrqEventTime = lastUpdate_ + ((256u - tima_) << timaClock[data & 3]) + 3;
|
||||
}
|
||||
|
||||
timaIrq.setNextIrqEventTime(nextIrqEventTime);
|
||||
}
|
||||
|
||||
tac_ = data;
|
||||
}
|
||||
|
||||
unsigned Tima::tima(unsigned long cycleCounter) {
|
||||
if (tac_ & 0x04)
|
||||
updateTima(cycleCounter);
|
||||
|
||||
return tima_;
|
||||
}
|
||||
|
||||
void Tima::doIrqEvent(const TimaInterruptRequester timaIrq) {
|
||||
timaIrq.flagIrq();
|
||||
timaIrq.setNextIrqEventTime(timaIrq.nextIrqEventTime() + ((256u - tma_) << timaClock[tac_ & 3]));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef TIMA_H
|
||||
#define TIMA_H
|
||||
|
||||
#include "interruptrequester.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class TimaInterruptRequester {
|
||||
InterruptRequester &intreq;
|
||||
|
||||
public:
|
||||
explicit TimaInterruptRequester(InterruptRequester &intreq) : intreq(intreq) {}
|
||||
void flagIrq() const { intreq.flagIrq(4); }
|
||||
unsigned long nextIrqEventTime() const { return intreq.eventTime(TIMA); }
|
||||
void setNextIrqEventTime(const unsigned long time) const { intreq.setEventTime<TIMA>(time); }
|
||||
};
|
||||
|
||||
class Tima {
|
||||
unsigned long lastUpdate_;
|
||||
unsigned long tmatime_;
|
||||
|
||||
unsigned char tima_;
|
||||
unsigned char tma_;
|
||||
unsigned char tac_;
|
||||
|
||||
void updateIrq(const unsigned long cc, const TimaInterruptRequester timaIrq) {
|
||||
while (cc >= timaIrq.nextIrqEventTime())
|
||||
doIrqEvent(timaIrq);
|
||||
}
|
||||
|
||||
void updateTima(unsigned long cc);
|
||||
|
||||
public:
|
||||
Tima();
|
||||
void saveState(SaveState &) const;
|
||||
void loadState(const SaveState &, TimaInterruptRequester timaIrq);
|
||||
void resetCc(unsigned long oldCc, unsigned long newCc, TimaInterruptRequester timaIrq);
|
||||
|
||||
void setTima(unsigned tima, unsigned long cc, TimaInterruptRequester timaIrq);
|
||||
void setTma(unsigned tma, unsigned long cc, TimaInterruptRequester timaIrq);
|
||||
void setTac(unsigned tac, unsigned long cc, TimaInterruptRequester timaIrq);
|
||||
unsigned tima(unsigned long cc);
|
||||
|
||||
void doIrqEvent(TimaInterruptRequester timaIrq);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,807 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "video.h"
|
||||
#include "savestate.h"
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
void LCD::setDmgPalette(unsigned long *const palette, const unsigned long *const dmgColors, const unsigned data) {
|
||||
palette[0] = dmgColors[data & 3];
|
||||
palette[1] = dmgColors[data >> 2 & 3];
|
||||
palette[2] = dmgColors[data >> 4 & 3];
|
||||
palette[3] = dmgColors[data >> 6 & 3];
|
||||
}
|
||||
|
||||
static unsigned long gbcToRgb32(const unsigned bgr15) {
|
||||
const unsigned long r = bgr15 & 0x1F;
|
||||
const unsigned long g = bgr15 >> 5 & 0x1F;
|
||||
const unsigned long b = bgr15 >> 10 & 0x1F;
|
||||
|
||||
return ((r * 13 + g * 2 + b) >> 1) << 16 | (g * 3 + b) << 9 | (r * 3 + g * 2 + b * 11) >> 1;
|
||||
}
|
||||
|
||||
/*static unsigned long gbcToRgb16(const unsigned bgr15) {
|
||||
const unsigned r = bgr15 & 0x1F;
|
||||
const unsigned g = bgr15 >> 5 & 0x1F;
|
||||
const unsigned b = bgr15 >> 10 & 0x1F;
|
||||
|
||||
return (((r * 13 + g * 2 + b + 8) << 7) & 0xF800) | ((g * 3 + b + 1) >> 1) << 5 | ((r * 3 + g * 2 + b * 11 + 8) >> 4);
|
||||
}
|
||||
|
||||
static unsigned long gbcToUyvy(const unsigned bgr15) {
|
||||
const unsigned r5 = bgr15 & 0x1F;
|
||||
const unsigned g5 = bgr15 >> 5 & 0x1F;
|
||||
const unsigned b5 = bgr15 >> 10 & 0x1F;
|
||||
|
||||
// y = (r5 * 926151 + g5 * 1723530 + b5 * 854319) / 510000 + 16;
|
||||
// u = (b5 * 397544 - r5 * 68824 - g5 * 328720) / 225930 + 128;
|
||||
// v = (r5 * 491176 - g5 * 328720 - b5 * 162456) / 178755 + 128;
|
||||
|
||||
const unsigned long y = (r5 * 116 + g5 * 216 + b5 * 107 + 16 * 64 + 32) >> 6;
|
||||
const unsigned long u = (b5 * 225 - r5 * 39 - g5 * 186 + 128 * 128 + 64) >> 7;
|
||||
const unsigned long v = (r5 * 176 - g5 * 118 - b5 * 58 + 128 * 64 + 32) >> 6;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
return u << 24 | y << 16 | v << 8 | y;
|
||||
#else
|
||||
return y << 24 | v << 16 | y << 8 | u;
|
||||
#endif
|
||||
}*/
|
||||
|
||||
LCD::LCD(const unsigned char *const oamram, const unsigned char *const vram, const VideoInterruptRequester memEventRequester) :
|
||||
ppu(nextM0Time_, oamram, vram),
|
||||
eventTimes_(memEventRequester),
|
||||
statReg(0),
|
||||
m2IrqStatReg_(0),
|
||||
m1IrqStatReg_(0)
|
||||
{
|
||||
std::memset( bgpData, 0, sizeof bgpData);
|
||||
std::memset(objpData, 0, sizeof objpData);
|
||||
|
||||
for (std::size_t i = 0; i < sizeof(dmgColorsRgb32) / sizeof(dmgColorsRgb32[0]); ++i)
|
||||
setDmgPaletteColor(i, (3 - (i & 3)) * 85 * 0x010101);
|
||||
|
||||
reset(oamram, vram, false);
|
||||
setVideoBuffer(0, 160);
|
||||
}
|
||||
|
||||
void LCD::reset(const unsigned char *const oamram, const unsigned char *vram, const bool cgb) {
|
||||
ppu.reset(oamram, vram, cgb);
|
||||
lycIrq.setCgb(cgb);
|
||||
refreshPalettes();
|
||||
}
|
||||
|
||||
static unsigned long mode2IrqSchedule(const unsigned statReg, const LyCounter &lyCounter, const unsigned long cycleCounter) {
|
||||
if (!(statReg & 0x20))
|
||||
return DISABLED_TIME;
|
||||
|
||||
unsigned next = lyCounter.time() - cycleCounter;
|
||||
|
||||
if (lyCounter.ly() >= 143 || (lyCounter.ly() == 142 && next <= 4) || (statReg & 0x08)) {
|
||||
next += (153u - lyCounter.ly()) * lyCounter.lineTime();
|
||||
} else {
|
||||
if (next <= 4)
|
||||
next += lyCounter.lineTime();
|
||||
|
||||
next -= 4;
|
||||
}
|
||||
|
||||
return cycleCounter + next;
|
||||
}
|
||||
|
||||
static inline unsigned long m0IrqTimeFromXpos166Time(const unsigned long xpos166Time, const bool cgb, const bool ds) {
|
||||
return xpos166Time + cgb - ds;
|
||||
}
|
||||
|
||||
static inline unsigned long hdmaTimeFromM0Time(const unsigned long m0Time, const bool ds) {
|
||||
return m0Time + 1 - ds;
|
||||
}
|
||||
|
||||
static unsigned long nextHdmaTime(const unsigned long lastM0Time,
|
||||
const unsigned long nextM0Time, const unsigned long cycleCounter, const bool ds) {
|
||||
return cycleCounter < hdmaTimeFromM0Time(lastM0Time, ds)
|
||||
? hdmaTimeFromM0Time(lastM0Time, ds)
|
||||
: hdmaTimeFromM0Time(nextM0Time, ds);
|
||||
}
|
||||
|
||||
void LCD::setStatePtrs(SaveState &state) {
|
||||
state.ppu.bgpData.set( bgpData, sizeof bgpData);
|
||||
state.ppu.objpData.set(objpData, sizeof objpData);
|
||||
ppu.setStatePtrs(state);
|
||||
}
|
||||
|
||||
void LCD::saveState(SaveState &state) const {
|
||||
state.mem.hdmaTransfer = hdmaIsEnabled();
|
||||
state.ppu.nextM0Irq = eventTimes_(MODE0_IRQ) - ppu.now();
|
||||
state.ppu.pendingLcdstatIrq = eventTimes_(ONESHOT_LCDSTATIRQ) != DISABLED_TIME;
|
||||
|
||||
lycIrq.saveState(state);
|
||||
m0Irq_.saveState(state);
|
||||
ppu.saveState(state);
|
||||
}
|
||||
|
||||
void LCD::loadState(const SaveState &state, const unsigned char *const oamram) {
|
||||
statReg = state.mem.ioamhram.get()[0x141];
|
||||
m2IrqStatReg_ = statReg;
|
||||
m1IrqStatReg_ = statReg;
|
||||
|
||||
ppu.loadState(state, oamram);
|
||||
lycIrq.loadState(state);
|
||||
m0Irq_.loadState(state);
|
||||
|
||||
if (ppu.lcdc() & 0x80) {
|
||||
nextM0Time_.predictNextM0Time(ppu);
|
||||
lycIrq.reschedule(ppu.lyCounter(), ppu.now());
|
||||
|
||||
eventTimes_.setm<ONESHOT_LCDSTATIRQ>(state.ppu.pendingLcdstatIrq
|
||||
? ppu.now() + 1 : static_cast<unsigned long>(DISABLED_TIME));
|
||||
eventTimes_.setm<ONESHOT_UPDATEWY2>(state.ppu.oldWy != state.mem.ioamhram.get()[0x14A]
|
||||
? ppu.now() + 1 : static_cast<unsigned long>(DISABLED_TIME));
|
||||
eventTimes_.set<LY_COUNT>(ppu.lyCounter().time());
|
||||
eventTimes_.setm<SPRITE_MAP>(SpriteMapper::schedule(ppu.lyCounter(), ppu.now()));
|
||||
eventTimes_.setm<LYC_IRQ>(lycIrq.time());
|
||||
eventTimes_.setm<MODE1_IRQ>(ppu.lyCounter().nextFrameCycle(144 * 456, ppu.now()));
|
||||
eventTimes_.setm<MODE2_IRQ>(mode2IrqSchedule(statReg, ppu.lyCounter(), ppu.now()));
|
||||
eventTimes_.setm<MODE0_IRQ>((statReg & 0x08) ? ppu.now() + state.ppu.nextM0Irq : static_cast<unsigned long>(DISABLED_TIME));
|
||||
eventTimes_.setm<HDMA_REQ>(state.mem.hdmaTransfer
|
||||
? nextHdmaTime(ppu.lastM0Time(), nextM0Time_.predictedNextM0Time(), ppu.now(), isDoubleSpeed())
|
||||
: static_cast<unsigned long>(DISABLED_TIME));
|
||||
} else for (int i = 0; i < NUM_MEM_EVENTS; ++i)
|
||||
eventTimes_.set(static_cast<MemEvent>(i), DISABLED_TIME);
|
||||
|
||||
refreshPalettes();
|
||||
}
|
||||
|
||||
void LCD::refreshPalettes() {
|
||||
if (ppu.cgb()) {
|
||||
for (unsigned i = 0; i < 8 * 8; i += 2) {
|
||||
ppu.bgPalette()[i >> 1] = gbcToRgb32( bgpData[i] | bgpData[i + 1] << 8);
|
||||
ppu.spPalette()[i >> 1] = gbcToRgb32(objpData[i] | objpData[i + 1] << 8);
|
||||
}
|
||||
} else {
|
||||
setDmgPalette(ppu.bgPalette() , dmgColorsRgb32 , bgpData[0]);
|
||||
setDmgPalette(ppu.spPalette() , dmgColorsRgb32 + 4, objpData[0]);
|
||||
setDmgPalette(ppu.spPalette() + 4, dmgColorsRgb32 + 8, objpData[1]);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template<class Blend>
|
||||
static void blitOsdElement(uint_least32_t *d,
|
||||
const uint_least32_t *s, const unsigned width, unsigned h, const int dpitch, Blend blend)
|
||||
{
|
||||
while (h--) {
|
||||
for (unsigned w = width; w--;) {
|
||||
if (*s != 0xFFFFFFFF)
|
||||
*d = blend(*s, *d);
|
||||
|
||||
++d;
|
||||
++s;
|
||||
}
|
||||
|
||||
d += dpitch - static_cast<int>(width);
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned weight>
|
||||
struct Blend {
|
||||
enum { SW = weight - 1 };
|
||||
enum { LOWMASK = SW * 0x010101ul };
|
||||
uint_least32_t operator()(const uint_least32_t s, const uint_least32_t d) const {
|
||||
return (s * SW + d - (((s & LOWMASK) * SW + (d & LOWMASK)) & LOWMASK)) / weight;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
static void clear(T *buf, const unsigned long color, const int dpitch) {
|
||||
unsigned lines = 144;
|
||||
|
||||
while (lines--) {
|
||||
std::fill_n(buf, 160, color);
|
||||
buf += dpitch;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LCD::updateScreen(const bool blanklcd, const unsigned long cycleCounter) {
|
||||
update(cycleCounter);
|
||||
|
||||
if (blanklcd && ppu.frameBuf().fb()) {
|
||||
const unsigned long color = ppu.cgb() ? gbcToRgb32(0xFFFF) : dmgColorsRgb32[0];
|
||||
clear(ppu.frameBuf().fb(), color, ppu.frameBuf().pitch());
|
||||
}
|
||||
|
||||
if (ppu.frameBuf().fb() && osdElement.get()) {
|
||||
if (const uint_least32_t *const s = osdElement->update()) {
|
||||
uint_least32_t *const d = ppu.frameBuf().fb()
|
||||
+ static_cast<long>(osdElement->y()) * ppu.frameBuf().pitch() + osdElement->x();
|
||||
|
||||
switch (osdElement->opacity()) {
|
||||
case OsdElement::SEVEN_EIGHTHS:
|
||||
blitOsdElement(d, s, osdElement->w(), osdElement->h(), ppu.frameBuf().pitch(), Blend<8>()); break;
|
||||
case OsdElement::THREE_FOURTHS:
|
||||
blitOsdElement(d, s, osdElement->w(), osdElement->h(), ppu.frameBuf().pitch(), Blend<4>()); break;
|
||||
}
|
||||
} else
|
||||
osdElement.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void LCD::resetCc(const unsigned long oldCc, const unsigned long newCc) {
|
||||
update(oldCc);
|
||||
ppu.resetCc(oldCc, newCc);
|
||||
|
||||
if (ppu.lcdc() & 0x80) {
|
||||
const unsigned long dec = oldCc - newCc;
|
||||
|
||||
nextM0Time_.invalidatePredictedNextM0Time();
|
||||
lycIrq.reschedule(ppu.lyCounter(), newCc);
|
||||
|
||||
for (int i = 0; i < NUM_MEM_EVENTS; ++i) {
|
||||
if (eventTimes_(static_cast<MemEvent>(i)) != DISABLED_TIME)
|
||||
eventTimes_.set(static_cast<MemEvent>(i), eventTimes_(static_cast<MemEvent>(i)) - dec);
|
||||
}
|
||||
|
||||
eventTimes_.set<LY_COUNT>(ppu.lyCounter().time());
|
||||
}
|
||||
}
|
||||
|
||||
void LCD::speedChange(const unsigned long cycleCounter) {
|
||||
update(cycleCounter);
|
||||
ppu.speedChange(cycleCounter);
|
||||
|
||||
if (ppu.lcdc() & 0x80) {
|
||||
nextM0Time_.predictNextM0Time(ppu);
|
||||
lycIrq.reschedule(ppu.lyCounter(), cycleCounter);
|
||||
|
||||
eventTimes_.set<LY_COUNT>(ppu.lyCounter().time());
|
||||
eventTimes_.setm<SPRITE_MAP>(SpriteMapper::schedule(ppu.lyCounter(), cycleCounter));
|
||||
eventTimes_.setm<LYC_IRQ>(lycIrq.time());
|
||||
eventTimes_.setm<MODE1_IRQ>(ppu.lyCounter().nextFrameCycle(144 * 456, cycleCounter));
|
||||
eventTimes_.setm<MODE2_IRQ>(mode2IrqSchedule(statReg, ppu.lyCounter(), cycleCounter));
|
||||
|
||||
if (eventTimes_(MODE0_IRQ) != DISABLED_TIME && eventTimes_(MODE0_IRQ) - cycleCounter > 1)
|
||||
eventTimes_.setm<MODE0_IRQ>(m0IrqTimeFromXpos166Time(ppu.predictedNextXposTime(166), ppu.cgb(), isDoubleSpeed()));
|
||||
|
||||
if (hdmaIsEnabled() && eventTimes_(HDMA_REQ) - cycleCounter > 1) {
|
||||
eventTimes_.setm<HDMA_REQ>(nextHdmaTime(ppu.lastM0Time(),
|
||||
nextM0Time_.predictedNextM0Time(), cycleCounter, isDoubleSpeed()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned long m0TimeOfCurrentLine(const unsigned long nextLyTime,
|
||||
const unsigned long lastM0Time, const unsigned long nextM0Time)
|
||||
{
|
||||
return nextM0Time < nextLyTime ? nextM0Time : lastM0Time;
|
||||
}
|
||||
|
||||
unsigned long LCD::m0TimeOfCurrentLine(const unsigned long cc) {
|
||||
if (cc >= nextM0Time_.predictedNextM0Time()) {
|
||||
update(cc);
|
||||
nextM0Time_.predictNextM0Time(ppu);
|
||||
}
|
||||
|
||||
return gambatte::m0TimeOfCurrentLine(ppu.lyCounter().time(), ppu.lastM0Time(), nextM0Time_.predictedNextM0Time());
|
||||
}
|
||||
|
||||
static bool isHdmaPeriod(const LyCounter &lyCounter,
|
||||
const unsigned long m0TimeOfCurrentLy, const unsigned long cycleCounter)
|
||||
{
|
||||
const unsigned timeToNextLy = lyCounter.time() - cycleCounter;
|
||||
|
||||
return /*(ppu.lcdc & 0x80) && */lyCounter.ly() < 144 && timeToNextLy > 4
|
||||
&& cycleCounter >= hdmaTimeFromM0Time(m0TimeOfCurrentLy, lyCounter.isDoubleSpeed());
|
||||
}
|
||||
|
||||
void LCD::enableHdma(const unsigned long cycleCounter) {
|
||||
if (cycleCounter >= nextM0Time_.predictedNextM0Time()) {
|
||||
update(cycleCounter);
|
||||
nextM0Time_.predictNextM0Time(ppu);
|
||||
} else if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
if (isHdmaPeriod(ppu.lyCounter(),
|
||||
gambatte::m0TimeOfCurrentLine(ppu.lyCounter().time(),
|
||||
ppu.lastM0Time(), nextM0Time_.predictedNextM0Time()), cycleCounter)) {
|
||||
eventTimes_.flagHdmaReq();
|
||||
}
|
||||
|
||||
eventTimes_.setm<HDMA_REQ>(nextHdmaTime(ppu.lastM0Time(), nextM0Time_.predictedNextM0Time(), cycleCounter, isDoubleSpeed()));
|
||||
}
|
||||
|
||||
void LCD::disableHdma(const unsigned long cycleCounter) {
|
||||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
eventTimes_.setm<HDMA_REQ>(DISABLED_TIME);
|
||||
}
|
||||
|
||||
bool LCD::vramAccessible(const unsigned long cycleCounter) {
|
||||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
return !(ppu.lcdc() & 0x80) || ppu.lyCounter().ly() >= 144
|
||||
|| ppu.lyCounter().lineCycles(cycleCounter) < 80U
|
||||
|| cycleCounter + isDoubleSpeed() - ppu.cgb() + 2 >= m0TimeOfCurrentLine(cycleCounter);
|
||||
}
|
||||
|
||||
bool LCD::cgbpAccessible(const unsigned long cycleCounter) {
|
||||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
return !(ppu.lcdc() & 0x80) || ppu.lyCounter().ly() >= 144
|
||||
|| ppu.lyCounter().lineCycles(cycleCounter) < 80U + isDoubleSpeed()
|
||||
|| cycleCounter >= m0TimeOfCurrentLine(cycleCounter) + 3 - isDoubleSpeed();
|
||||
}
|
||||
|
||||
static void doCgbColorChange(unsigned char *const pdata,
|
||||
unsigned long *const palette, unsigned index, const unsigned data) {
|
||||
pdata[index] = data;
|
||||
index >>= 1;
|
||||
palette[index] = gbcToRgb32(pdata[index << 1] | pdata[(index << 1) + 1] << 8);
|
||||
}
|
||||
|
||||
void LCD::doCgbBgColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (cgbpAccessible(cycleCounter)) {
|
||||
update(cycleCounter);
|
||||
doCgbColorChange(bgpData, ppu.bgPalette(), index, data);
|
||||
}
|
||||
}
|
||||
|
||||
void LCD::doCgbSpColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (cgbpAccessible(cycleCounter)) {
|
||||
update(cycleCounter);
|
||||
doCgbColorChange(objpData, ppu.spPalette(), index, data);
|
||||
}
|
||||
}
|
||||
|
||||
bool LCD::oamReadable(const unsigned long cycleCounter) {
|
||||
if (!(ppu.lcdc() & 0x80) || ppu.inactivePeriodAfterDisplayEnable(cycleCounter))
|
||||
return true;
|
||||
|
||||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
if (ppu.lyCounter().lineCycles(cycleCounter) + 4 - ppu.lyCounter().isDoubleSpeed() * 3u >= 456)
|
||||
return ppu.lyCounter().ly() >= 144-1 && ppu.lyCounter().ly() != 153;
|
||||
|
||||
return ppu.lyCounter().ly() >= 144 || cycleCounter + isDoubleSpeed() - ppu.cgb() + 2 >= m0TimeOfCurrentLine(cycleCounter);
|
||||
}
|
||||
|
||||
bool LCD::oamWritable(const unsigned long cycleCounter) {
|
||||
if (!(ppu.lcdc() & 0x80) || ppu.inactivePeriodAfterDisplayEnable(cycleCounter))
|
||||
return true;
|
||||
|
||||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
if (ppu.lyCounter().lineCycles(cycleCounter) + 3 + ppu.cgb() - ppu.lyCounter().isDoubleSpeed() * 2u >= 456)
|
||||
return ppu.lyCounter().ly() >= 144-1 && ppu.lyCounter().ly() != 153;
|
||||
|
||||
return ppu.lyCounter().ly() >= 144 || cycleCounter + isDoubleSpeed() - ppu.cgb() + 2 >= m0TimeOfCurrentLine(cycleCounter);
|
||||
}
|
||||
|
||||
void LCD::mode3CyclesChange() {
|
||||
nextM0Time_.invalidatePredictedNextM0Time();
|
||||
|
||||
if (eventTimes_(MODE0_IRQ) != DISABLED_TIME
|
||||
&& eventTimes_(MODE0_IRQ) > m0IrqTimeFromXpos166Time(ppu.now(), ppu.cgb(), isDoubleSpeed())) {
|
||||
eventTimes_.setm<MODE0_IRQ>(m0IrqTimeFromXpos166Time(ppu.predictedNextXposTime(166), ppu.cgb(), isDoubleSpeed()));
|
||||
}
|
||||
|
||||
if (eventTimes_(HDMA_REQ) != DISABLED_TIME
|
||||
&& eventTimes_(HDMA_REQ) > hdmaTimeFromM0Time(ppu.lastM0Time(), isDoubleSpeed())) {
|
||||
nextM0Time_.predictNextM0Time(ppu);
|
||||
eventTimes_.setm<HDMA_REQ>(hdmaTimeFromM0Time(nextM0Time_.predictedNextM0Time(), isDoubleSpeed()));
|
||||
}
|
||||
}
|
||||
|
||||
void LCD::wxChange(const unsigned newValue, const unsigned long cycleCounter) {
|
||||
update(cycleCounter + isDoubleSpeed() + 1);
|
||||
ppu.setWx(newValue);
|
||||
mode3CyclesChange();
|
||||
}
|
||||
|
||||
void LCD::wyChange(const unsigned newValue, const unsigned long cycleCounter) {
|
||||
update(cycleCounter + 1);
|
||||
ppu.setWy(newValue);
|
||||
// mode3CyclesChange(); // should be safe to wait until after wy2 delay, because no mode3 events are close to when wy1 is read.
|
||||
|
||||
// wy2 is a delayed version of wy. really just slowness of ly == wy comparison.
|
||||
if (ppu.cgb() && (ppu.lcdc() & 0x80)) {
|
||||
eventTimes_.setm<ONESHOT_UPDATEWY2>(cycleCounter + 5);
|
||||
} else {
|
||||
update(cycleCounter + 2);
|
||||
ppu.updateWy2();
|
||||
mode3CyclesChange();
|
||||
}
|
||||
}
|
||||
|
||||
void LCD::scxChange(const unsigned newScx, const unsigned long cycleCounter) {
|
||||
update(cycleCounter + ppu.cgb() + isDoubleSpeed());
|
||||
ppu.setScx(newScx);
|
||||
mode3CyclesChange();
|
||||
}
|
||||
|
||||
void LCD::scyChange(const unsigned newValue, const unsigned long cycleCounter) {
|
||||
update(cycleCounter + ppu.cgb() + isDoubleSpeed());
|
||||
ppu.setScy(newValue);
|
||||
}
|
||||
|
||||
void LCD::oamChange(const unsigned long cycleCounter) {
|
||||
if (ppu.lcdc() & 0x80) {
|
||||
update(cycleCounter);
|
||||
ppu.oamChange(cycleCounter);
|
||||
eventTimes_.setm<SPRITE_MAP>(SpriteMapper::schedule(ppu.lyCounter(), cycleCounter));
|
||||
}
|
||||
}
|
||||
|
||||
void LCD::oamChange(const unsigned char *const oamram, const unsigned long cycleCounter) {
|
||||
update(cycleCounter);
|
||||
ppu.oamChange(oamram, cycleCounter);
|
||||
|
||||
if (ppu.lcdc() & 0x80)
|
||||
eventTimes_.setm<SPRITE_MAP>(SpriteMapper::schedule(ppu.lyCounter(), cycleCounter));
|
||||
}
|
||||
|
||||
void LCD::lcdcChange(const unsigned data, const unsigned long cycleCounter) {
|
||||
const unsigned oldLcdc = ppu.lcdc();
|
||||
update(cycleCounter);
|
||||
|
||||
if ((oldLcdc ^ data) & 0x80) {
|
||||
ppu.setLcdc(data, cycleCounter);
|
||||
|
||||
if (data & 0x80) {
|
||||
lycIrq.lcdReset();
|
||||
m0Irq_.lcdReset(statReg, lycIrq.lycReg());
|
||||
|
||||
if (lycIrq.lycReg() == 0 && (statReg & 0x40))
|
||||
eventTimes_.flagIrq(2);
|
||||
|
||||
nextM0Time_.predictNextM0Time(ppu);
|
||||
lycIrq.reschedule(ppu.lyCounter(), cycleCounter);
|
||||
|
||||
eventTimes_.set<LY_COUNT>(ppu.lyCounter().time());
|
||||
eventTimes_.setm<SPRITE_MAP>(SpriteMapper::schedule(ppu.lyCounter(), cycleCounter));
|
||||
eventTimes_.setm<LYC_IRQ>(lycIrq.time());
|
||||
eventTimes_.setm<MODE1_IRQ>(ppu.lyCounter().nextFrameCycle(144 * 456, cycleCounter));
|
||||
eventTimes_.setm<MODE2_IRQ>(mode2IrqSchedule(statReg, ppu.lyCounter(), cycleCounter));
|
||||
|
||||
if (statReg & 0x08)
|
||||
eventTimes_.setm<MODE0_IRQ>(m0IrqTimeFromXpos166Time(ppu.predictedNextXposTime(166), ppu.cgb(), isDoubleSpeed()));
|
||||
|
||||
if (hdmaIsEnabled()) {
|
||||
eventTimes_.setm<HDMA_REQ>(nextHdmaTime(ppu.lastM0Time(),
|
||||
nextM0Time_.predictedNextM0Time(), cycleCounter, isDoubleSpeed()));
|
||||
}
|
||||
} else for (int i = 0; i < NUM_MEM_EVENTS; ++i)
|
||||
eventTimes_.set(static_cast<MemEvent>(i), DISABLED_TIME);
|
||||
} else if (data & 0x80) {
|
||||
if (ppu.cgb()) {
|
||||
ppu.setLcdc((oldLcdc & ~0x14) | (data & 0x14), cycleCounter);
|
||||
|
||||
if ((oldLcdc ^ data) & 0x04)
|
||||
eventTimes_.setm<SPRITE_MAP>(SpriteMapper::schedule(ppu.lyCounter(), cycleCounter));
|
||||
|
||||
update(cycleCounter + isDoubleSpeed() + 1);
|
||||
ppu.setLcdc(data, cycleCounter + isDoubleSpeed() + 1);
|
||||
|
||||
if ((oldLcdc ^ data) & 0x20)
|
||||
mode3CyclesChange();
|
||||
} else {
|
||||
ppu.setLcdc(data, cycleCounter);
|
||||
|
||||
if ((oldLcdc ^ data) & 0x04)
|
||||
eventTimes_.setm<SPRITE_MAP>(SpriteMapper::schedule(ppu.lyCounter(), cycleCounter));
|
||||
|
||||
if ((oldLcdc ^ data) & 0x22)
|
||||
mode3CyclesChange();
|
||||
}
|
||||
} else
|
||||
ppu.setLcdc(data, cycleCounter);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct LyCnt {
|
||||
unsigned ly; int timeToNextLy;
|
||||
LyCnt(unsigned ly, int timeToNextLy) : ly(ly), timeToNextLy(timeToNextLy) {}
|
||||
};
|
||||
|
||||
static LyCnt const getLycCmpLy(LyCounter const &lyCounter, unsigned long cc) {
|
||||
unsigned ly = lyCounter.ly();
|
||||
int timeToNextLy = lyCounter.time() - cc;
|
||||
|
||||
if (ly == 153) {
|
||||
if (timeToNextLy - (448 << lyCounter.isDoubleSpeed()) > 0) {
|
||||
timeToNextLy -= (448 << lyCounter.isDoubleSpeed());
|
||||
} else {
|
||||
ly = 0;
|
||||
timeToNextLy += lyCounter.lineTime();
|
||||
}
|
||||
}
|
||||
|
||||
return LyCnt(ly, timeToNextLy);
|
||||
}
|
||||
}
|
||||
|
||||
void LCD::lcdstatChange(unsigned const data, unsigned long const cycleCounter) {
|
||||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
unsigned const old = statReg;
|
||||
statReg = data;
|
||||
lycIrq.statRegChange(data, ppu.lyCounter(), cycleCounter);
|
||||
|
||||
if (ppu.lcdc() & 0x80) {
|
||||
int const timeToNextLy = ppu.lyCounter().time() - cycleCounter;
|
||||
LyCnt const lycCmp = getLycCmpLy(ppu.lyCounter(), cycleCounter);
|
||||
|
||||
if (!ppu.cgb()) {
|
||||
if (ppu.lyCounter().ly() < 144) {
|
||||
if (cycleCounter + 1 < m0TimeOfCurrentLine(cycleCounter)) {
|
||||
if (lycCmp.ly == lycIrq.lycReg() && !(old & 0x40))
|
||||
eventTimes_.flagIrq(2);
|
||||
} else {
|
||||
if (!(old & 0x08) && !(lycCmp.ly == lycIrq.lycReg() && (old & 0x40)))
|
||||
eventTimes_.flagIrq(2);
|
||||
}
|
||||
} else {
|
||||
if (!(old & 0x10) && !(lycCmp.ly == lycIrq.lycReg() && (old & 0x40)))
|
||||
eventTimes_.flagIrq(2);
|
||||
}
|
||||
} else if (data & ~old & 0x78) {
|
||||
bool const lycperiod = lycCmp.ly == lycIrq.lycReg() && lycCmp.timeToNextLy > 4 - isDoubleSpeed() * 4;
|
||||
|
||||
if (!(lycperiod && (old & 0x40))) {
|
||||
if (ppu.lyCounter().ly() < 144) {
|
||||
if (cycleCounter + isDoubleSpeed() * 2 < m0TimeOfCurrentLine(cycleCounter) || timeToNextLy <= 4) {
|
||||
if (lycperiod && (data & 0x40))
|
||||
eventTimes_.flagIrq(2);
|
||||
} else if (!(old & 0x08)) {
|
||||
if ((data & 0x08) || (lycperiod && (data & 0x40)))
|
||||
eventTimes_.flagIrq(2);
|
||||
}
|
||||
} else if (!(old & 0x10)) {
|
||||
if ((data & 0x10) && (ppu.lyCounter().ly() < 153 || timeToNextLy > 4 - isDoubleSpeed() * 4)) {
|
||||
eventTimes_.flagIrq(2);
|
||||
} else if (lycperiod && (data & 0x40))
|
||||
eventTimes_.flagIrq(2);
|
||||
}
|
||||
}
|
||||
|
||||
if ((data & 0x28) == 0x20 && !(old & 0x20)
|
||||
&& ((timeToNextLy <= 4 && ppu.lyCounter().ly() < 143)
|
||||
|| (timeToNextLy == 456*2 && ppu.lyCounter().ly() < 144))) {
|
||||
eventTimes_.flagIrq(2);
|
||||
}
|
||||
}
|
||||
|
||||
if ((data & 0x08) && eventTimes_(MODE0_IRQ) == DISABLED_TIME) {
|
||||
update(cycleCounter);
|
||||
eventTimes_.setm<MODE0_IRQ>(m0IrqTimeFromXpos166Time(ppu.predictedNextXposTime(166), ppu.cgb(), isDoubleSpeed()));
|
||||
}
|
||||
|
||||
eventTimes_.setm<MODE2_IRQ>(mode2IrqSchedule(data, ppu.lyCounter(), cycleCounter));
|
||||
eventTimes_.setm<LYC_IRQ>(lycIrq.time());
|
||||
}
|
||||
|
||||
m2IrqStatReg_ = eventTimes_(MODE2_IRQ) - cycleCounter > (ppu.cgb() - isDoubleSpeed()) * 4U
|
||||
? data : (m2IrqStatReg_ & 0x10) | (statReg & ~0x10);
|
||||
m1IrqStatReg_ = eventTimes_(MODE1_IRQ) - cycleCounter > (ppu.cgb() - isDoubleSpeed()) * 4U
|
||||
? data : (m1IrqStatReg_ & 0x08) | (statReg & ~0x08);
|
||||
|
||||
m0Irq_.statRegChange(data, eventTimes_(MODE0_IRQ), cycleCounter, ppu.cgb());
|
||||
}
|
||||
|
||||
void LCD::lycRegChange(unsigned const data, unsigned long const cycleCounter) {
|
||||
unsigned const old = lycIrq.lycReg();
|
||||
|
||||
if (data == old)
|
||||
return;
|
||||
|
||||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
m0Irq_.lycRegChange(data, eventTimes_(MODE0_IRQ), cycleCounter, isDoubleSpeed(), ppu.cgb());
|
||||
lycIrq.lycRegChange(data, ppu.lyCounter(), cycleCounter);
|
||||
|
||||
if (!(ppu.lcdc() & 0x80))
|
||||
return;
|
||||
|
||||
eventTimes_.setm<LYC_IRQ>(lycIrq.time());
|
||||
|
||||
int const timeToNextLy = ppu.lyCounter().time() - cycleCounter;
|
||||
|
||||
if ((statReg & 0x40) && data < 154
|
||||
&& (ppu.lyCounter().ly() < 144
|
||||
? !(statReg & 0x08) || cycleCounter < m0TimeOfCurrentLine(cycleCounter) || timeToNextLy <= 4 << ppu.cgb()
|
||||
: !(statReg & 0x10) || (ppu.lyCounter().ly() == 153 && timeToNextLy <= 4 && ppu.cgb() && !isDoubleSpeed()))) {
|
||||
LyCnt lycCmp = getLycCmpLy(ppu.lyCounter(), cycleCounter);
|
||||
|
||||
if (lycCmp.timeToNextLy <= 4 << ppu.cgb()) {
|
||||
lycCmp.ly = old != lycCmp.ly || (lycCmp.timeToNextLy <= 4 && ppu.cgb() && !isDoubleSpeed())
|
||||
? (lycCmp.ly == 153 ? 0 : lycCmp.ly + 1)
|
||||
: 0xFF; // simultaneous ly/lyc inc. lyc flag never goes low -> no trigger.
|
||||
}
|
||||
|
||||
if (data == lycCmp.ly) {
|
||||
if (ppu.cgb() && !isDoubleSpeed()) {
|
||||
eventTimes_.setm<ONESHOT_LCDSTATIRQ>(cycleCounter + 5);
|
||||
} else
|
||||
eventTimes_.flagIrq(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned LCD::getStat(unsigned const lycReg, unsigned long const cycleCounter) {
|
||||
unsigned stat = 0;
|
||||
|
||||
if (ppu.lcdc() & 0x80) {
|
||||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
int const timeToNextLy = ppu.lyCounter().time() - cycleCounter;
|
||||
|
||||
if (ppu.lyCounter().ly() > 143) {
|
||||
if (ppu.lyCounter().ly() < 153 || timeToNextLy > 4 - isDoubleSpeed() * 4)
|
||||
stat = 1;
|
||||
} else {
|
||||
unsigned const lineCycles = 456 - (timeToNextLy >> isDoubleSpeed());
|
||||
|
||||
if (lineCycles < 80) {
|
||||
if (!ppu.inactivePeriodAfterDisplayEnable(cycleCounter))
|
||||
stat = 2;
|
||||
} else if (cycleCounter + isDoubleSpeed() - ppu.cgb() + 2 < m0TimeOfCurrentLine(cycleCounter))
|
||||
stat = 3;
|
||||
}
|
||||
|
||||
LyCnt const lycCmp = getLycCmpLy(ppu.lyCounter(), cycleCounter);
|
||||
|
||||
if (lycReg == lycCmp.ly && lycCmp.timeToNextLy > 4 - isDoubleSpeed() * 4)
|
||||
stat |= 4;
|
||||
}
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
inline void LCD::doMode2IrqEvent() {
|
||||
const unsigned ly = eventTimes_(LY_COUNT) - eventTimes_(MODE2_IRQ) < 8
|
||||
? (ppu.lyCounter().ly() == 153 ? 0 : ppu.lyCounter().ly() + 1)
|
||||
: ppu.lyCounter().ly();
|
||||
|
||||
if ((ly != 0 || !(m2IrqStatReg_ & 0x10)) &&
|
||||
(!(m2IrqStatReg_ & 0x40) || (lycIrq.lycReg() != 0 ? ly != (lycIrq.lycReg() + 1U) : ly > 1))) {
|
||||
eventTimes_.flagIrq(2);
|
||||
}
|
||||
|
||||
m2IrqStatReg_ = statReg;
|
||||
|
||||
if (!(statReg & 0x08)) {
|
||||
unsigned long nextTime = eventTimes_(MODE2_IRQ) + ppu.lyCounter().lineTime();
|
||||
|
||||
if (ly == 0) {
|
||||
nextTime -= 4;
|
||||
} else if (ly == 143)
|
||||
nextTime += ppu.lyCounter().lineTime() * 10 + 4;
|
||||
|
||||
eventTimes_.setm<MODE2_IRQ>(nextTime);
|
||||
} else
|
||||
eventTimes_.setm<MODE2_IRQ>(eventTimes_(MODE2_IRQ) + (70224 << isDoubleSpeed()));
|
||||
}
|
||||
|
||||
inline void LCD::event() {
|
||||
switch (eventTimes_.nextEvent()) {
|
||||
case MEM_EVENT:
|
||||
switch (eventTimes_.nextMemEvent()) {
|
||||
case MODE1_IRQ:
|
||||
eventTimes_.flagIrq((m1IrqStatReg_ & 0x18) == 0x10 ? 3 : 1);
|
||||
m1IrqStatReg_ = statReg;
|
||||
eventTimes_.setm<MODE1_IRQ>(eventTimes_(MODE1_IRQ) + (70224 << isDoubleSpeed()));
|
||||
break;
|
||||
|
||||
case LYC_IRQ: {
|
||||
unsigned char ifreg = 0;
|
||||
lycIrq.doEvent(&ifreg, ppu.lyCounter());
|
||||
eventTimes_.flagIrq(ifreg);
|
||||
eventTimes_.setm<LYC_IRQ>(lycIrq.time());
|
||||
break;
|
||||
}
|
||||
|
||||
case SPRITE_MAP:
|
||||
eventTimes_.setm<SPRITE_MAP>(ppu.doSpriteMapEvent(eventTimes_(SPRITE_MAP)));
|
||||
mode3CyclesChange();
|
||||
break;
|
||||
|
||||
case HDMA_REQ:
|
||||
eventTimes_.flagHdmaReq();
|
||||
nextM0Time_.predictNextM0Time(ppu);
|
||||
eventTimes_.setm<HDMA_REQ>(hdmaTimeFromM0Time(nextM0Time_.predictedNextM0Time(), isDoubleSpeed()));
|
||||
break;
|
||||
|
||||
case MODE2_IRQ:
|
||||
doMode2IrqEvent();
|
||||
break;
|
||||
|
||||
case MODE0_IRQ:
|
||||
{
|
||||
unsigned char ifreg = 0;
|
||||
m0Irq_.doEvent(&ifreg, ppu.lyCounter().ly(), statReg, lycIrq.lycReg());
|
||||
eventTimes_.flagIrq(ifreg);
|
||||
}
|
||||
|
||||
eventTimes_.setm<MODE0_IRQ>((statReg & 0x08)
|
||||
? m0IrqTimeFromXpos166Time(ppu.predictedNextXposTime(166), ppu.cgb(), isDoubleSpeed())
|
||||
: static_cast<unsigned long>(DISABLED_TIME));
|
||||
break;
|
||||
|
||||
case ONESHOT_LCDSTATIRQ:
|
||||
eventTimes_.flagIrq(2);
|
||||
eventTimes_.setm<ONESHOT_LCDSTATIRQ>(DISABLED_TIME);
|
||||
break;
|
||||
|
||||
case ONESHOT_UPDATEWY2:
|
||||
ppu.updateWy2();
|
||||
mode3CyclesChange();
|
||||
eventTimes_.setm<ONESHOT_UPDATEWY2>(DISABLED_TIME);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LY_COUNT:
|
||||
ppu.doLyCountEvent();
|
||||
eventTimes_.set<LY_COUNT>(ppu.lyCounter().time());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void LCD::update(const unsigned long cycleCounter) {
|
||||
if (!(ppu.lcdc() & 0x80))
|
||||
return;
|
||||
|
||||
while (cycleCounter >= eventTimes_.nextEventTime()) {
|
||||
ppu.update(eventTimes_.nextEventTime());
|
||||
event();
|
||||
}
|
||||
|
||||
ppu.update(cycleCounter);
|
||||
}
|
||||
|
||||
void LCD::setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) {
|
||||
ppu.setFrameBuf(videoBuf, pitch);
|
||||
}
|
||||
|
||||
void LCD::setDmgPaletteColor(const unsigned index, const unsigned long rgb32) {
|
||||
dmgColorsRgb32[index] = rgb32;
|
||||
}
|
||||
|
||||
void LCD::setDmgPaletteColor(const unsigned palNum, const unsigned colorNum, const unsigned long rgb32) {
|
||||
if (palNum > 2 || colorNum > 3)
|
||||
return;
|
||||
|
||||
setDmgPaletteColor(palNum * 4 | colorNum, rgb32);
|
||||
refreshPalettes();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,257 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef VIDEO_H
|
||||
#define VIDEO_H
|
||||
|
||||
#include "video/ppu.h"
|
||||
#include "video/lyc_irq.h"
|
||||
#include "video/next_m0_time.h"
|
||||
#include "interruptrequester.h"
|
||||
#include "osd_element.h"
|
||||
#include "minkeeper.h"
|
||||
#include <memory>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class VideoInterruptRequester {
|
||||
InterruptRequester * intreq;
|
||||
|
||||
public:
|
||||
explicit VideoInterruptRequester(InterruptRequester * intreq) : intreq(intreq) {}
|
||||
void flagHdmaReq() const { gambatte::flagHdmaReq(intreq); }
|
||||
void flagIrq(const unsigned bit) const { intreq->flagIrq(bit); }
|
||||
void setNextEventTime(const unsigned long time) const { intreq->setEventTime<VIDEO>(time); }
|
||||
};
|
||||
|
||||
class M0Irq {
|
||||
unsigned char statReg_;
|
||||
unsigned char lycReg_;
|
||||
|
||||
public:
|
||||
M0Irq() : statReg_(0), lycReg_(0) {}
|
||||
|
||||
void lcdReset(const unsigned statReg, const unsigned lycReg) {
|
||||
statReg_ = statReg;
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
void statRegChange(const unsigned statReg,
|
||||
const unsigned long nextM0IrqTime, const unsigned long cc, const bool cgb) {
|
||||
if (nextM0IrqTime - cc > cgb * 2U)
|
||||
statReg_ = statReg;
|
||||
}
|
||||
|
||||
void lycRegChange(const unsigned lycReg,
|
||||
const unsigned long nextM0IrqTime, const unsigned long cc, const bool ds, const bool cgb) {
|
||||
if (nextM0IrqTime - cc > cgb * 5 + 1U - ds)
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
void doEvent(unsigned char *const ifreg, const unsigned ly, const unsigned statReg, const unsigned lycReg) {
|
||||
if (((statReg_ | statReg) & 0x08) && (!(statReg_ & 0x40) || ly != lycReg_))
|
||||
*ifreg |= 2;
|
||||
|
||||
statReg_ = statReg;
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
void saveState(SaveState &state) const {
|
||||
state.ppu.m0lyc = lycReg_;
|
||||
}
|
||||
|
||||
void loadState(const SaveState &state) {
|
||||
lycReg_ = state.ppu.m0lyc;
|
||||
statReg_ = state.mem.ioamhram.get()[0x141];
|
||||
}
|
||||
|
||||
unsigned statReg() const { return statReg_; }
|
||||
};
|
||||
|
||||
class LCD {
|
||||
enum Event { MEM_EVENT, LY_COUNT }; enum { NUM_EVENTS = LY_COUNT + 1 };
|
||||
enum MemEvent { ONESHOT_LCDSTATIRQ, ONESHOT_UPDATEWY2, MODE1_IRQ, LYC_IRQ, SPRITE_MAP,
|
||||
HDMA_REQ, MODE2_IRQ, MODE0_IRQ }; enum { NUM_MEM_EVENTS = MODE0_IRQ + 1 };
|
||||
|
||||
class EventTimes {
|
||||
MinKeeper<NUM_EVENTS> eventMin_;
|
||||
MinKeeper<NUM_MEM_EVENTS> memEventMin_;
|
||||
VideoInterruptRequester memEventRequester_;
|
||||
|
||||
void setMemEvent() {
|
||||
const unsigned long nmet = nextMemEventTime();
|
||||
eventMin_.setValue<MEM_EVENT>(nmet);
|
||||
memEventRequester_.setNextEventTime(nmet);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit EventTimes(const VideoInterruptRequester memEventRequester) : memEventRequester_(memEventRequester) {}
|
||||
|
||||
Event nextEvent() const { return static_cast<Event>(eventMin_.min()); }
|
||||
unsigned long nextEventTime() const { return eventMin_.minValue(); }
|
||||
unsigned long operator()(const Event e) const { return eventMin_.value(e); }
|
||||
template<Event e> void set(const unsigned long time) { eventMin_.setValue<e>(time); }
|
||||
void set(const Event e, const unsigned long time) { eventMin_.setValue(e, time); }
|
||||
|
||||
MemEvent nextMemEvent() const { return static_cast<MemEvent>(memEventMin_.min()); }
|
||||
unsigned long nextMemEventTime() const { return memEventMin_.minValue(); }
|
||||
unsigned long operator()(const MemEvent e) const { return memEventMin_.value(e); }
|
||||
template<MemEvent e> void setm(const unsigned long time) { memEventMin_.setValue<e>(time); setMemEvent(); }
|
||||
void set(const MemEvent e, const unsigned long time) { memEventMin_.setValue(e, time); setMemEvent(); }
|
||||
|
||||
void flagIrq(const unsigned bit) { memEventRequester_.flagIrq(bit); }
|
||||
void flagHdmaReq() { memEventRequester_.flagHdmaReq(); }
|
||||
};
|
||||
|
||||
PPU ppu;
|
||||
unsigned long dmgColorsRgb32[3 * 4];
|
||||
unsigned char bgpData[8 * 8];
|
||||
unsigned char objpData[8 * 8];
|
||||
|
||||
EventTimes eventTimes_;
|
||||
M0Irq m0Irq_;
|
||||
LycIrq lycIrq;
|
||||
NextM0Time nextM0Time_;
|
||||
|
||||
std::auto_ptr<OsdElement> osdElement;
|
||||
|
||||
unsigned char statReg;
|
||||
unsigned char m2IrqStatReg_;
|
||||
unsigned char m1IrqStatReg_;
|
||||
|
||||
static void setDmgPalette(unsigned long *palette, const unsigned long *dmgColors, unsigned data);
|
||||
void setDmgPaletteColor(unsigned index, unsigned long rgb32);
|
||||
|
||||
void refreshPalettes();
|
||||
void setDBuffer();
|
||||
|
||||
void doMode2IrqEvent();
|
||||
void event();
|
||||
|
||||
unsigned long m0TimeOfCurrentLine(unsigned long cc);
|
||||
bool cgbpAccessible(unsigned long cycleCounter);
|
||||
|
||||
void mode3CyclesChange();
|
||||
void doCgbBgColorChange(unsigned index, unsigned data, unsigned long cycleCounter);
|
||||
void doCgbSpColorChange(unsigned index, unsigned data, unsigned long cycleCounter);
|
||||
|
||||
public:
|
||||
LCD(const unsigned char *oamram, const unsigned char *vram_in, VideoInterruptRequester memEventRequester);
|
||||
void reset(const unsigned char *oamram, const unsigned char *vram, bool cgb);
|
||||
void setStatePtrs(SaveState &state);
|
||||
void saveState(SaveState &state) const;
|
||||
void loadState(const SaveState &state, const unsigned char *oamram);
|
||||
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32);
|
||||
void setVideoBuffer(uint_least32_t *videoBuf, int pitch);
|
||||
|
||||
void setOsdElement(std::auto_ptr<OsdElement> osdElement) { this->osdElement = osdElement; }
|
||||
|
||||
void dmgBgPaletteChange(const unsigned data, const unsigned long cycleCounter) {
|
||||
update(cycleCounter);
|
||||
bgpData[0] = data;
|
||||
setDmgPalette(ppu.bgPalette(), dmgColorsRgb32, data);
|
||||
}
|
||||
|
||||
void dmgSpPalette1Change(const unsigned data, const unsigned long cycleCounter) {
|
||||
update(cycleCounter);
|
||||
objpData[0] = data;
|
||||
setDmgPalette(ppu.spPalette(), dmgColorsRgb32 + 4, data);
|
||||
}
|
||||
|
||||
void dmgSpPalette2Change(const unsigned data, const unsigned long cycleCounter) {
|
||||
update(cycleCounter);
|
||||
objpData[1] = data;
|
||||
setDmgPalette(ppu.spPalette() + 4, dmgColorsRgb32 + 8, data);
|
||||
}
|
||||
|
||||
void cgbBgColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (bgpData[index] != data)
|
||||
doCgbBgColorChange(index, data, cycleCounter);
|
||||
}
|
||||
|
||||
void cgbSpColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (objpData[index] != data)
|
||||
doCgbSpColorChange(index, data, cycleCounter);
|
||||
}
|
||||
|
||||
unsigned cgbBgColorRead(const unsigned index, const unsigned long cycleCounter) {
|
||||
return ppu.cgb() & cgbpAccessible(cycleCounter) ? bgpData[index] : 0xFF;
|
||||
}
|
||||
|
||||
unsigned cgbSpColorRead(const unsigned index, const unsigned long cycleCounter) {
|
||||
return ppu.cgb() & cgbpAccessible(cycleCounter) ? objpData[index] : 0xFF;
|
||||
}
|
||||
|
||||
void updateScreen(bool blanklcd, unsigned long cc);
|
||||
void resetCc(unsigned long oldCC, unsigned long newCc);
|
||||
void speedChange(unsigned long cycleCounter);
|
||||
bool vramAccessible(unsigned long cycleCounter);
|
||||
bool oamReadable(unsigned long cycleCounter);
|
||||
bool oamWritable(unsigned long cycleCounter);
|
||||
void wxChange(unsigned newValue, unsigned long cycleCounter);
|
||||
void wyChange(unsigned newValue, unsigned long cycleCounter);
|
||||
void oamChange(unsigned long cycleCounter);
|
||||
void oamChange(const unsigned char *oamram, unsigned long cycleCounter);
|
||||
void scxChange(unsigned newScx, unsigned long cycleCounter);
|
||||
void scyChange(unsigned newValue, unsigned long cycleCounter);
|
||||
|
||||
void vramChange(const unsigned long cycleCounter) { update(cycleCounter); }
|
||||
|
||||
unsigned getStat(unsigned lycReg, unsigned long cycleCounter);
|
||||
|
||||
unsigned getLyReg(const unsigned long cycleCounter) {
|
||||
unsigned lyReg = 0;
|
||||
|
||||
if (ppu.lcdc() & 0x80) {
|
||||
if (cycleCounter >= ppu.lyCounter().time())
|
||||
update(cycleCounter);
|
||||
|
||||
lyReg = ppu.lyCounter().ly();
|
||||
|
||||
if (lyReg == 153) {
|
||||
if (isDoubleSpeed()) {
|
||||
if (ppu.lyCounter().time() - cycleCounter <= 456 * 2 - 8)
|
||||
lyReg = 0;
|
||||
} else
|
||||
lyReg = 0;
|
||||
} else if (ppu.lyCounter().time() - cycleCounter <= 4)
|
||||
++lyReg;
|
||||
}
|
||||
|
||||
return lyReg;
|
||||
}
|
||||
|
||||
unsigned long nextMode1IrqTime() const { return eventTimes_(MODE1_IRQ); }
|
||||
|
||||
void lcdcChange(unsigned data, unsigned long cycleCounter);
|
||||
void lcdstatChange(unsigned data, unsigned long cycleCounter);
|
||||
void lycRegChange(unsigned data, unsigned long cycleCounter);
|
||||
|
||||
void enableHdma(unsigned long cycleCounter);
|
||||
void disableHdma(unsigned long cycleCounter);
|
||||
bool hdmaIsEnabled() const { return eventTimes_(HDMA_REQ) != DISABLED_TIME; }
|
||||
|
||||
void update(unsigned long cycleCounter);
|
||||
|
||||
bool isCgb() const { return ppu.cgb(); }
|
||||
bool isDoubleSpeed() const { return ppu.lyCounter().isDoubleSpeed(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,68 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "ly_counter.h"
|
||||
#include "../savestate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
LyCounter::LyCounter()
|
||||
: time_(0), lineTime_(0), ly_(0), ds(false)
|
||||
{
|
||||
setDoubleSpeed(false);
|
||||
reset(0, 0);
|
||||
}
|
||||
|
||||
void LyCounter::doEvent() {
|
||||
++ly_;
|
||||
|
||||
if (ly_ == 154)
|
||||
ly_ = 0;
|
||||
|
||||
time_ = time_ + lineTime_;
|
||||
}
|
||||
|
||||
unsigned long LyCounter::nextLineCycle(const unsigned lineCycle, const unsigned long cycleCounter) const {
|
||||
unsigned long tmp = time_ + (lineCycle << ds);
|
||||
|
||||
if (tmp - cycleCounter > lineTime_)
|
||||
tmp -= lineTime_;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
unsigned long LyCounter::nextFrameCycle(const unsigned long frameCycle, const unsigned long cycleCounter) const {
|
||||
unsigned long tmp = time_ + (((153U - ly()) * 456U + frameCycle) << ds);
|
||||
|
||||
if (tmp - cycleCounter > 70224U << ds)
|
||||
tmp -= 70224U << ds;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void LyCounter::reset(const unsigned long videoCycles, const unsigned long lastUpdate) {
|
||||
ly_ = videoCycles / 456;
|
||||
time_ = lastUpdate + ((456 - (videoCycles - ly_ * 456ul)) << isDoubleSpeed());
|
||||
}
|
||||
|
||||
void LyCounter::setDoubleSpeed(const bool ds_in) {
|
||||
ds = ds_in;
|
||||
lineTime_ = 456U << ds_in;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user