67 Commits

Author SHA1 Message Date
clobber ef91ce464c Cleanup 2023-06-20 21:13:53 -06:00
clobber 0ba54f14d3 Merge pull request #8 from ShutOstrich/master
Update to Gambatte JG 0.5.1
2023-05-03 21:20:11 -06:00
ShutOstrich 0a330b490f Add display mode: CGB color correction 2023-05-01 18:55:17 +02:00
ShutOstrich 65e0083de0 Update to Gambatte JG 0.5.1 2023-05-01 07:39:23 +02:00
ShutOstrich 6237b9f50e Update to Gambatte JG 0.5.0 2023-05-01 07:39:23 +02:00
clobber ba04dbb4ef Merge pull request #7 from OpenEmu/revert-5-master
Revert "Add: Colour Palette Revisions"
2021-12-09 21:05:46 -07:00
clobber 2fffad141d Revert "Add: Colour Palette Revisions" 2021-12-09 21:02:29 -07:00
C.W. Betts 44182cc6eb Merge pull request #5 from TRIFORCE89/master
Add: Colour Palette Revisions
2021-12-09 19:21:12 -07:00
TRIFORCE89 72bb48afdd - Finally accurate SGB colours
- Remove usage of BGB colours
2021-12-02 20:16:14 -05:00
TRIFORCE89 ecbaa4142b correct SGB specific palettes; add real WideBoy values; add missing Smurfs from Goomba 2021-09-18 10:00:50 -04:00
TRIFORCE89 e69312eabd Redo Demo Vision after correcting NES Classic Mini palette in Nestopia 2021-07-23 21:24:24 -04:00
TRIFORCE89 b5a97f1d55 Multiple Revisions
Changes:
 - Double check against TheWolfBunny & nensondubois
 - improved commenting
 - nensondubois' revised Alley Way SGB palette
 - nensondubois' revised Tetris Attack SGB palette
 - Collection of SaGa palette
 - Donkey Kong '94 ending palette
 - SGB Super Mario Land palette for Arne's Unnamed Graphics Hack rather than 1-A
 - Wide-Boy palette option
 - Donkey Kong Land DMGesque menu palette option
 - Game & Watch palette option
 - Demo Vision palette option
 - remove unused palette additions (Superball, Squidlit)
 - update Dream Land GB with TheWolfBunny's version
2021-07-16 12:01:05 -04:00
TRIFORCE89 00e8ac983c Add: SGB Cool Spot from NP. Some unofficial Goomba Color entries for other games 2021-06-11 21:58:02 -04:00
TRIFORCE89 be62b682da MGB is default again (I play with LCD grids), swap Squidlit for proper GB Studio 2021-06-06 12:30:51 -04:00
TRIFORCE89 8868472869 Fix: Kirby Pocket && Add: custom Arne SML2013 (need to edit game header to activate) 2021-05-19 08:53:37 -04:00
TRIFORCE89 beba11c372 Kirby!
Changes:
- Fix: Wii Gray is now the default
- Add: Smash Ultimate Green replaces VC Green
- Fix: revise true color output

Note:
- new green palette was created by pushing LUT (https://scanmountgoat.github.io/Smush-Material-Research/post_processing) through https://hexcolor.co/image-to-colors and increasing brightness by 40%
- 3DS Dreamland GB looked like 3DS VC, so in my view Switch Dreamland GB is a TV-safe revision of that VC palette
2021-05-12 00:24:18 -04:00
TRIFORCE89 5c1a41ec41 Updates:
- rearrange palette menu
- add back SGB 4H (My Life in Gaming endorses it)
- replace 3DS grayscale with the nicer revision from Kirby's Dream Collection
- SGB Pokémon taken from disassembly
- accurate GB Studio
- code cleanup

Notes:
- recommended to not use a LCD-tint (like GBC/GBA/GBI) shader on SGB palettes
2021-05-10 20:21:24 -04:00
TRIFORCE89 01f163576d Fix: locations of the system plugin headers.
Changes:
- Minor Xcode maintenance.
2020-12-25 14:09:15 -05:00
TRIFORCE89 be0e841c42 Add: SGB/GBC support for Lunar Chase prototype 2020-10-23 00:28:03 -04:00
C.W. Betts 40e9ff65bb Poke the plists: get the development language from Xcode build. 2020-10-01 01:51:37 -06:00
C.W. Betts c4bd988726 Fix locations of the system plugin headers.
Minor Xcode maintenance.
2020-10-01 01:26:40 -06:00
C.W. Betts 17ccc013a8 Revert "set deployment target to match OpenEmuCore's, of 10.14.4." 2020-09-22 09:30:09 -06:00
C.W. Betts bb866b0f91 set deployment target to match OpenEmuCore's, of 10.14.4.
Also silence deprecated OpenGL warnings.
2020-09-22 02:53:07 -06:00
TRIFORCE89 ac3ceae429 Add: palette for Analogue Pocket / GB Studio 2020-09-20 19:14:11 -04:00
TRIFORCE89 69a6fe7856 Tweak PkMn palettes to match VBA-M and TheWolfBunny 2020-09-20 19:14:11 -04:00
TRIFORCE89 5fd058a7ea True Colour
Changes:
 - Remove: Gambatte's incorrect colour correction (this should be addressed via shaders)
 - Fix: change up the list of available palette selections again because now they all actually look correct
2020-09-20 19:13:16 -04:00
TRIFORCE89 f463dc6b7a Add: GBC Greyscale option & default to VC Greyscale instead of SGB as it approximates Pocket 2020-09-20 19:06:07 -04:00
TRIFORCE89 d8d6f0d807 Add: VirtualBoy palette 2020-09-20 19:06:07 -04:00
TRIFORCE89 08f893779e Fix: revise palettes used and include VC colours 2020-09-20 19:06:07 -04:00
TRIFORCE89 23b9a5de5a Add: Colour Palette Revisions 2020-09-20 19:06:07 -04:00
clobber e5b42325c9 Revert version number back to "counting" upstream commits
Counting the commits like other forks (https://github.com/pokemon-speedrunning/gambatte-speedrun) until there is a formal release again. NOTE: counting by `git rev-list --count HEAD` instead of `git rev-list --count --first-parent HEAD`
2020-08-20 12:23:49 -05:00
clobber fb4cc1323e Merge MBC3 RTC crash fix from https://github.com/sinamas/gambatte/pull/18 2020-08-20 11:59:52 -05:00
clobber 8e6c44a63e Bump version for sparkle updater 2020-08-20 01:42:56 -05:00
clobber 052a4b7020 Sync with upstream https://github.com/sinamas/gambatte/commit/56e3371151b5ee86dcdcf4868324ebc6de220bc9
This also includes our serialize/deserialize support and GBC GameShark cheat fixes from commits 9fbc420 and d08f236
2020-08-20 01:34:31 -05:00
Daniele Cattaneo fd5294ab09 Disable code signing.
Could cause problems with Sparkle in a future update built with a recent version of Xcode.
2020-08-16 18:03:41 +02:00
Daniele Cattaneo 3ee18feec9 Quiet Xcode warnings. 2020-08-16 15:42:50 +02:00
Daniele Cattaneo a69f54e944 Prevent passing too many samples to the resampler when playing certain games (i.e. Mario Tennis).
Fixes issue #6 (and its duplicate OpenEmu/OpenEmu#4282).
2020-08-16 15:14:23 +02:00
C.W. Betts c1823b4021 Update language resources.
This quiets warnings in newer Xcode releases.

Also update framework locations.
2020-01-07 16:37:18 -07:00
clobber 27b26480c6 Bump version for sparkle updater. Core is still 0.5.0 r572 2018-11-26 14:38:32 -06:00
clobber fd071b24b5 Cleanup 2018-11-26 14:37:03 -06:00
clobber 34bc63a962 More cleanup 2018-11-10 23:42:40 -06:00
clobber 41e7cbb149 Cleanup 2018-11-07 10:51:08 -06:00
clobber 4cc81aa4ac Add display mode change support 2018-11-04 13:10:46 -06:00
clobber eac78b39e1 Use -fileSystemRepresentation instead of -UTF8String for file names 2017-08-16 23:48:03 -05:00
Rudy Richter 8245238796 Use spaces 2017-07-20 08:51:07 -04:00
mrvacbob d16ec11885 Enable direct-rendering 2017-07-20 01:59:11 -07:00
clobber 3d80d60170 Bump version for sparkle updater. Core is still 0.5.0 r572 2016-07-01 12:00:27 -05:00
clobber 4674e6e71d Limit rewind buffer to 60 seconds to reduce memory use 2016-06-30 01:31:54 -05:00
clobber 4269e63ba9 Clean up deprecated methods. 2015-12-12 17:04:33 -08:00
Alexander Strange 9596973f2b Update projects - fix debug builds, make deployment 10.11, enable objc-arc properly, build faster 2015-10-17 13:04:19 -07:00
clobber 817ae4c84b Turn off GCC_NO_COMMON_BLOCKS 2015-10-09 19:33:02 -05:00
Christoph Leimbrock ada23edf7f Fix some warning and adjust project settings. 2015-10-06 22:04:35 +02:00
Kyle Lacy f5ba2b307d Add plist keys to support rewinding 2015-05-16 06:50:59 -07:00
Kyle Lacy f11164a1f4 Add core serialization/deserialization 2015-05-16 06:50:50 -07:00
Kyle Lacy 0f1f2580f1 Add serialize/deserialize functions to GB class 2015-05-16 06:32:43 -07:00
Kyle Lacy 4ab0b010b2 Add StateSaver stream serializing/deserializing functions 2015-05-16 06:31:34 -07:00
Kyle Lacy 6790464f1c Refactor gambatte read/write functions
All read/write functions now deal with general streams
(`istream`/`ostream`) instead of file streams (`ifstream`/`ofstream`)
2015-05-16 06:30:50 -07:00
clobber f4bb22c7b0 Restore cheat fixes from commits 9fbc420dfb and d08f236239 2015-03-18 15:03:16 -05:00
clobber 344384e397 Fix audio buffer size 2015-03-15 01:27:00 -05:00
clobber 55778fe610 Update Gambatte to latest upstream at https://github.com/sinamas/gambatte/commit/46e06da8bd4907edabaddd8d588d6a11c3dd90f1 2015-03-14 03:33:29 -05:00
clobber 64da32c6d6 Directly apply custom palettes 2014-07-27 22:47:42 -05:00
clobber ffbd062550 Bump version in order for sparkle updater to work. Core is still 0.5.0 r364 2014-07-27 22:32:58 -05:00
clobber 7ddebab56a Add “Display Mode” special key support for toggling GBC palette presets 2014-07-27 22:32:05 -05:00
clobber 272a093957 Use proper biosDirectoryPath 2014-07-27 13:49:06 -05:00
clobber ac7031c753 Don't poll input every time input is fetched 2014-07-26 21:27:50 -05:00
clobber 2c314f92ee Full enable/disable support for cheats 2014-07-26 21:16:25 -05:00
clobber 9fbc420dfb Decode GBC GameShark cheats prefixed with 91xxxxxx
Apparently these should mean a "WRAM Write with Bank Change" (Changes to ram bank 1, then writes 0xHH to 0xHHHH), but Gambatte decodes and applies these fine. Fixes many GBC cheats out in the wild that are prefixed as 91xxxxxx
2014-07-26 21:14:29 -05:00
216 changed files with 17945 additions and 28952 deletions
+339
View File
@@ -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.
+551
View File
@@ -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
-71
View File
@@ -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
-35
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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>
+58
View File
@@ -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/)
-56
View File
@@ -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;
}
-34
View File
@@ -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
-94
View File
@@ -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;
}
-66
View File
@@ -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
-170
View File
@@ -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();
}
-172
View File
@@ -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
-244
View File
@@ -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
-380
View File
@@ -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
-246
View File
@@ -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
-112
View File
@@ -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
-35
View File
@@ -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;
}
-37
View File
@@ -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
-31
View File
@@ -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
-158
View File
@@ -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;
}
}
-30
View File
@@ -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
-48
View File
@@ -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];
}
-39
View File
@@ -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
-179
View File
@@ -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);
}
-39
View File
@@ -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
-345
View File
@@ -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);
}
-39
View File
@@ -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
-234
View File
@@ -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);
}
-39
View File
@@ -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
-39
View File
@@ -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
-39
View File
@@ -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
-30
View File
@@ -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
+2
View File
@@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */
File diff suppressed because it is too large Load Diff
-56
View File
@@ -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)
-166
View File
@@ -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
-62
View File
@@ -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
-33
View File
@@ -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
-429
View File
@@ -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; }
-573
View File
@@ -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
-87
View File
@@ -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
-104
View File
@@ -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
-217
View File
@@ -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()));
}
-132
View File
@@ -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
-177
View File
@@ -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;
}
-75
View File
@@ -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
-358
View File
@@ -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 */
-208
View File
@@ -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);
}
}
-26
View File
@@ -1,26 +0,0 @@
/***************************************************************************
* Copyright (C) 2008 by Sindre Aams *
* 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
-51
View File
@@ -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*/
-71
View File
@@ -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);
}
}
}
-47
View File
@@ -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
-103
View File
@@ -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));
}
}
-92
View File
@@ -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
-730
View File
@@ -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();
}
}
-154
View File
@@ -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
-139
View File
@@ -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;
}
}
}
}
-85
View File
@@ -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
-156
View File
@@ -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;
}
}
-91
View File
@@ -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
-160
View File
@@ -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
-147
View File
@@ -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
-68
View File
@@ -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
-182
View File
@@ -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;
}
}
-95
View File
@@ -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
-262
View File
@@ -1,262 +0,0 @@
/***************************************************************************
* Copyright (C) 2007 by Sindre Aams *
* 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;
}
}
}
-94
View File
@@ -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
-165
View File
@@ -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;
}
}
}
-73
View File
@@ -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
-207
View File
@@ -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;
}
}
}
-103
View File
@@ -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
-304
View File
@@ -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;
}
}
}
-102
View File
@@ -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
-152
View File
@@ -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();
}
}
-68
View File
@@ -1,68 +0,0 @@
/***************************************************************************
* Copyright (C) 2007 by Sindre Aams *
* 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
-106
View File
@@ -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;
}
}
-54
View File
@@ -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
-91
View File
@@ -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;
}
}
-48
View File
@@ -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
-33
View File
@@ -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
-39
View File
@@ -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
-183
View File
@@ -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));
}
}
-32
View File
@@ -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
-524
View File
@@ -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();
}
}
-48
View File
@@ -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
-171
View File
@@ -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]));
}
}
-67
View File
@@ -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
-807
View File
@@ -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();
}
}
-257
View File
@@ -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
-68
View File
@@ -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