From b3583386136d119305183336d66194a87ae8bc1b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 9 Dec 2021 01:03:05 -0500 Subject: [PATCH] arcade: minor optimization --- .gitmodules | 4 - CMakeLists.txt | 2 +- README.md | 2 +- extern/Nuked-OPM | 1 - extern/opm/LICENSE | 504 ++++++++ extern/opm/README.md | 6 + extern/opm/opm.c | 2003 ++++++++++++++++++++++++++++++++ extern/opm/opm.h | 269 +++++ src/engine/platform/arcade.cpp | 6 +- src/engine/platform/arcade.h | 2 +- 10 files changed, 2788 insertions(+), 11 deletions(-) delete mode 160000 extern/Nuked-OPM create mode 100644 extern/opm/LICENSE create mode 100644 extern/opm/README.md create mode 100644 extern/opm/opm.c create mode 100644 extern/opm/opm.h diff --git a/.gitmodules b/.gitmodules index 5716e0559..12644aff0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,10 +5,6 @@ path = extern/SDL url = https://github.com/libsdl-org/SDL.git branch = main -[submodule "extern/Nuked-OPM"] - path = extern/Nuked-OPM - url = https://github.com/nukeykt/Nuked-OPM - branch = main [submodule "extern/libsndfile"] path = extern/libsndfile url = https://github.com/libsndfile/libsndfile.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 56ee4cd32..bf99a5128 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ set(ENGINE_SOURCES src/log.cpp extern/Nuked-OPN2/ym3438.c -extern/Nuked-OPM/opm.c +extern/opm/opm.c src/engine/platform/sound/sn76496.cpp src/engine/platform/sound/gb/apu.c src/engine/platform/sound/gb/timing.c diff --git a/README.md b/README.md index e84b96b86..d51faf74d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ this is a work-in-progress chip music player (currently) for the .dmf format. ## features -- supports Sega Genesis, Master System, Game Boy, PC Engine, NES and C64 (for now, with more systems coming soon) +- supports Sega Genesis, Master System, Game Boy, PC Engine, NES, C64 and YM2151/PCM (Neo Geo coming soon) - clean-room design (zero reverse-engineered code and zero decompilation; using official DMF specs, guesswork and ABX tests only) - bug/quirk implementation for increased playback accuracy - accurate emulation cores (Nuked, MAME, SameBoy, Mednafen PCE, puNES and reSID (hahaha!)) diff --git a/extern/Nuked-OPM b/extern/Nuked-OPM deleted file mode 160000 index cc63f6fa9..000000000 --- a/extern/Nuked-OPM +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cc63f6fa962ec30f937cb95a47345d43c4720b04 diff --git a/extern/opm/LICENSE b/extern/opm/LICENSE new file mode 100644 index 000000000..8000a6faa --- /dev/null +++ b/extern/opm/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random + Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/extern/opm/README.md b/extern/opm/README.md new file mode 100644 index 000000000..0b01c58f0 --- /dev/null +++ b/extern/opm/README.md @@ -0,0 +1,6 @@ +# Nuked-OPM +Cycle accurate YM2151 emulator + +# modified + +this is a slightly modified version that strips out timer and CSM emulation to slightly reduce CPU usage. diff --git a/extern/opm/opm.c b/extern/opm/opm.c new file mode 100644 index 000000000..7a776fc06 --- /dev/null +++ b/extern/opm/opm.c @@ -0,0 +1,2003 @@ +/* Nuked OPM + * Copyright (C) 2020 Nuke.YKT + * + * This file is part of Nuked OPM. + * + * Nuked OPM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 + * of the License, or (at your option) any later version. + * + * Nuked OPM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Nuked OPM. If not, see . + * + * Nuked OPM emulator. + * Thanks: + * siliconpr0n.org(digshadow, John McMaster): + * YM2151 and other FM chip decaps and die shots. + * + * version: 0.9.2 beta + */ +#include +#include +#include "opm.h" + +enum { + eg_num_attack = 0, + eg_num_decay = 1, + eg_num_sustain = 2, + eg_num_release = 3 +}; + +/* logsin table */ +static const uint16_t logsinrom[256] = { + 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, + 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365, + 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, + 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261, + 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, + 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd, + 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, + 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166, + 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, + 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118, + 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, + 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db, + 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, + 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9, + 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, + 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081, + 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, + 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060, + 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, + 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045, + 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, + 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f, + 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, + 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e, + 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, + 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011, + 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, + 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007, + 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, + 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002, + 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 +}; + +/* exp table */ +static const uint16_t exprom[256] = { + 0x7fa, 0x7f5, 0x7ef, 0x7ea, 0x7e4, 0x7df, 0x7da, 0x7d4, + 0x7cf, 0x7c9, 0x7c4, 0x7bf, 0x7b9, 0x7b4, 0x7ae, 0x7a9, + 0x7a4, 0x79f, 0x799, 0x794, 0x78f, 0x78a, 0x784, 0x77f, + 0x77a, 0x775, 0x770, 0x76a, 0x765, 0x760, 0x75b, 0x756, + 0x751, 0x74c, 0x747, 0x742, 0x73d, 0x738, 0x733, 0x72e, + 0x729, 0x724, 0x71f, 0x71a, 0x715, 0x710, 0x70b, 0x706, + 0x702, 0x6fd, 0x6f8, 0x6f3, 0x6ee, 0x6e9, 0x6e5, 0x6e0, + 0x6db, 0x6d6, 0x6d2, 0x6cd, 0x6c8, 0x6c4, 0x6bf, 0x6ba, + 0x6b5, 0x6b1, 0x6ac, 0x6a8, 0x6a3, 0x69e, 0x69a, 0x695, + 0x691, 0x68c, 0x688, 0x683, 0x67f, 0x67a, 0x676, 0x671, + 0x66d, 0x668, 0x664, 0x65f, 0x65b, 0x657, 0x652, 0x64e, + 0x649, 0x645, 0x641, 0x63c, 0x638, 0x634, 0x630, 0x62b, + 0x627, 0x623, 0x61e, 0x61a, 0x616, 0x612, 0x60e, 0x609, + 0x605, 0x601, 0x5fd, 0x5f9, 0x5f5, 0x5f0, 0x5ec, 0x5e8, + 0x5e4, 0x5e0, 0x5dc, 0x5d8, 0x5d4, 0x5d0, 0x5cc, 0x5c8, + 0x5c4, 0x5c0, 0x5bc, 0x5b8, 0x5b4, 0x5b0, 0x5ac, 0x5a8, + 0x5a4, 0x5a0, 0x59c, 0x599, 0x595, 0x591, 0x58d, 0x589, + 0x585, 0x581, 0x57e, 0x57a, 0x576, 0x572, 0x56f, 0x56b, + 0x567, 0x563, 0x560, 0x55c, 0x558, 0x554, 0x551, 0x54d, + 0x549, 0x546, 0x542, 0x53e, 0x53b, 0x537, 0x534, 0x530, + 0x52c, 0x529, 0x525, 0x522, 0x51e, 0x51b, 0x517, 0x514, + 0x510, 0x50c, 0x509, 0x506, 0x502, 0x4ff, 0x4fb, 0x4f8, + 0x4f4, 0x4f1, 0x4ed, 0x4ea, 0x4e7, 0x4e3, 0x4e0, 0x4dc, + 0x4d9, 0x4d6, 0x4d2, 0x4cf, 0x4cc, 0x4c8, 0x4c5, 0x4c2, + 0x4be, 0x4bb, 0x4b8, 0x4b5, 0x4b1, 0x4ae, 0x4ab, 0x4a8, + 0x4a4, 0x4a1, 0x49e, 0x49b, 0x498, 0x494, 0x491, 0x48e, + 0x48b, 0x488, 0x485, 0x482, 0x47e, 0x47b, 0x478, 0x475, + 0x472, 0x46f, 0x46c, 0x469, 0x466, 0x463, 0x460, 0x45d, + 0x45a, 0x457, 0x454, 0x451, 0x44e, 0x44b, 0x448, 0x445, + 0x442, 0x43f, 0x43c, 0x439, 0x436, 0x433, 0x430, 0x42d, + 0x42a, 0x428, 0x425, 0x422, 0x41f, 0x41c, 0x419, 0x416, + 0x414, 0x411, 0x40e, 0x40b, 0x408, 0x406, 0x403, 0x400 +}; + +/* Envelope generator */ +static const uint32_t eg_stephi[4][4] = { + { 0, 0, 0, 0 }, + { 1, 0, 0, 0 }, + { 1, 0, 1, 0 }, + { 1, 1, 1, 0 } +}; + +/* Phase generator */ +static const uint32_t pg_detune[8] = { 16, 17, 19, 20, 22, 24, 27, 29 }; + +typedef struct { + int32_t basefreq; + int32_t approxtype; + int32_t slope; +} freqtable_t; + +static const freqtable_t pg_freqtable[64] = { + { 1299, 1, 19 }, + { 1318, 1, 19 }, + { 1337, 1, 19 }, + { 1356, 1, 20 }, + { 1376, 1, 20 }, + { 1396, 1, 20 }, + { 1416, 1, 21 }, + { 1437, 1, 20 }, + { 1458, 1, 21 }, + { 1479, 1, 21 }, + { 1501, 1, 22 }, + { 1523, 1, 22 }, + { 0, 0, 16 }, + { 0, 0, 16 }, + { 0, 0, 16 }, + { 0, 0, 16 }, + { 1545, 1, 22 }, + { 1567, 1, 22 }, + { 1590, 1, 23 }, + { 1613, 1, 23 }, + { 1637, 1, 23 }, + { 1660, 1, 24 }, + { 1685, 1, 24 }, + { 1709, 1, 24 }, + { 1734, 1, 25 }, + { 1759, 1, 25 }, + { 1785, 1, 26 }, + { 1811, 1, 26 }, + { 0, 0, 16 }, + { 0, 0, 16 }, + { 0, 0, 16 }, + { 0, 0, 16 }, + { 1837, 1, 26 }, + { 1864, 1, 27 }, + { 1891, 1, 27 }, + { 1918, 1, 28 }, + { 1946, 1, 28 }, + { 1975, 1, 28 }, + { 2003, 1, 29 }, + { 2032, 1, 30 }, + { 2062, 1, 30 }, + { 2092, 1, 30 }, + { 2122, 1, 31 }, + { 2153, 1, 31 }, + { 0, 0, 16 }, + { 0, 0, 16 }, + { 0, 0, 16 }, + { 0, 0, 16 }, + { 2185, 1, 31 }, + { 2216, 0, 31 }, + { 2249, 0, 31 }, + { 2281, 0, 31 }, + { 2315, 0, 31 }, + { 2348, 0, 31 }, + { 2382, 0, 30 }, + { 2417, 0, 30 }, + { 2452, 0, 30 }, + { 2488, 0, 30 }, + { 2524, 0, 30 }, + { 2561, 0, 30 }, + { 0, 0, 16 }, + { 0, 0, 16 }, + { 0, 0, 16 }, + { 0, 0, 16 } +}; + + +/* FM algorithm */ +static const uint32_t fm_algorithm[4][6][8] = { + { + { 1, 1, 1, 1, 1, 1, 1, 1 }, /* M1_0 */ + { 1, 1, 1, 1, 1, 1, 1, 1 }, /* M1_1 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* C1 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ + { 0, 0, 0, 0, 0, 0, 0, 1 } /* Out */ + }, + { + { 0, 1, 0, 0, 0, 1, 0, 0 }, /* M1_0 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* M1_1 */ + { 1, 1, 1, 0, 0, 0, 0, 0 }, /* C1 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ + { 0, 0, 0, 0, 0, 1, 1, 1 } /* Out */ + }, + { + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* M1_0 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* M1_1 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* C1 */ + { 1, 0, 0, 1, 1, 1, 1, 0 }, /* Last operator */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* Last operator */ + { 0, 0, 0, 0, 1, 1, 1, 1 } /* Out */ + }, + { + { 0, 0, 1, 0, 0, 1, 0, 0 }, /* M1_0 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* M1_1 */ + { 0, 0, 0, 1, 0, 0, 0, 0 }, /* C1 */ + { 1, 1, 0, 1, 1, 0, 0, 0 }, /* Last operator */ + { 0, 0, 1, 0, 0, 0, 0, 0 }, /* Last operator */ + { 1, 1, 1, 1, 1, 1, 1, 1 } /* Out */ + } +}; + +static uint16_t lfo_counter2_table[] = { + 0x0000, 0x4000, 0x6000, 0x7000, + 0x7800, 0x7c00, 0x7e00, 0x7f00, + 0x7f80, 0x7fc0, 0x7fe0, 0x7ff0, + 0x7ff8, 0x7ffc, 0x7ffe, 0x7fff +}; + +static inline int32_t OPM_KCToFNum(int32_t kcode) +{ + int32_t kcode_h = (kcode >> 4) & 63; + int32_t kcode_l = kcode & 15; + int32_t i, slope, sum = 0; + if (pg_freqtable[kcode_h].approxtype) + { + for (i = 0; i < 4; i++) + { + if (kcode_l & (1 << i)) + { + sum += (pg_freqtable[kcode_h].slope >> (3 - i)); + } + } + } + else + { + slope = pg_freqtable[kcode_h].slope | 1; + if (kcode_l & 1) + { + sum += (slope >> 3) + 2; + } + if (kcode_l & 2) + { + sum += 8; + } + if (kcode_l & 4) + { + sum += slope >> 1; + } + if (kcode_l & 8) + { + sum += slope; + sum++; + } + if ((kcode_l & 12) == 12 && (pg_freqtable[kcode_h].slope & 1) == 0) + { + sum += 4; + } + } + return pg_freqtable[kcode_h].basefreq + (sum >> 1); +} + +static inline int32_t OPM_LFOApplyPMS(int32_t lfo, int32_t pms) +{ + int32_t t, out; + int32_t top = (lfo >> 4) & 7; + if (pms != 7) + { + top >>= 1; + } + t = (top & 6) == 6 || ((top & 3) == 3 && pms >= 6); + + out = top + ((top >> 2) & 1) + t; + out = out * 2 + ((lfo >> 4) & 1); + + if (pms == 7) + { + out >>= 1; + } + out &= 15; + out = (lfo & 15) + out * 16; + switch (pms) + { + case 0: + default: + out = 0; + break; + case 1: + out = (out >> 5) & 3; + break; + case 2: + out = (out >> 4) & 7; + break; + case 3: + out = (out >> 3) & 15; + break; + case 4: + out = (out >> 2) & 31; + break; + case 5: + out = (out >> 1) & 63; + break; + case 6: + out = (out & 255) << 1; + break; + case 7: + out = (out & 255) << 2; + break; + } + return out; +} + +static inline int32_t OPM_CalcKCode(int32_t kcf, int32_t lfo, int32_t lfo_sign, int32_t dt) +{ + int32_t t2, t3, b0, b1, b2, b3, w2, w3, w6; + int32_t overflow1 = 0; + int32_t overflow2 = 0; + int32_t negoverflow = 0; + int32_t sum, cr; + if (!lfo_sign) + { + lfo = ~lfo; + } + sum = (kcf & 8191) + (lfo&8191) + (!lfo_sign); + cr = ((kcf & 255) + (lfo & 255) + (!lfo_sign)) >> 8; + if (sum & (1 << 13)) + { + overflow1 = 1; + } + sum &= 8191; + if (lfo_sign && ((((sum >> 6) & 3) == 3) || cr)) + { + sum += 64; + } + if (!lfo_sign && !cr) + { + sum += (-64)&8191; + negoverflow = 1; + } + if (sum & (1 << 13)) + { + overflow2 = 1; + } + sum &= 8191; + if ((!lfo_sign && !overflow1) || (negoverflow && !overflow2)) + { + sum = 0; + } + if (lfo_sign && (overflow1 || overflow2)) + { + sum = 8127; + } + + t2 = sum & 63; + if (dt == 2) + t2 += 20; + if (dt == 2 || dt == 3) + t2 += 32; + + b0 = (t2 >> 6) & 1; + b1 = dt == 2; + b2 = ((sum >> 6) & 1); + b3 = ((sum >> 7) & 1); + + + w2 = (b0 && b1 && b2); + w3 = (b0 && b3); + w6 = (b0 && !w2 && !w3) || (b3 && !b0 && b1); + + t2 &= 63; + + t3 = (sum >> 6) + w6 + b1 + (w2 || w3) * 2 + (dt == 3) * 4 + (dt != 0) * 8; + if (t3 & 128) + { + t2 = 63; + t3 = 126; + } + sum = t3 * 64 + t2; + return sum; +} + +static inline void OPM_PhaseCalcFNumBlock(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 7) % 32; + uint32_t channel = slot % 8; + uint32_t kcf = (chip->ch_kc[channel] << 6) + chip->ch_kf[channel]; + uint32_t lfo = chip->lfo_pmd ? chip->lfo_pm_lock : 0; + uint32_t pms = chip->ch_pms[channel]; + uint32_t dt = chip->sl_dt2[slot]; + int32_t lfo_pm = OPM_LFOApplyPMS(lfo & 127, pms); + uint32_t kcode = OPM_CalcKCode(kcf, lfo_pm, (lfo & 0x80) != 0 && pms != 0 ? 0 : 1, dt); + uint32_t fnum = OPM_KCToFNum(kcode); + uint32_t kcode_h = kcode >> 8; + chip->pg_fnum[slot] = fnum; + chip->pg_kcode[slot] = kcode_h; +} + +static inline void OPM_PhaseCalcIncrement(opm_t *chip) +{ + uint32_t slot = chip->cycles; + uint32_t channel = slot % 8; + uint32_t dt = chip->sl_dt1[slot]; + uint32_t dt_l = dt & 3; + uint32_t detune = 0; + uint32_t multi = chip->sl_mul[slot]; + uint32_t kcode = chip->pg_kcode[slot]; + uint32_t fnum = chip->pg_fnum[slot]; + uint32_t block = kcode >> 2; + uint32_t basefreq = (fnum << block) >> 2; + uint32_t note, sum, sum_h, sum_l, inc; + /* Apply detune */ + if (dt_l) + { + if (kcode > 0x1c) + { + kcode = 0x1c; + } + block = kcode >> 2; + note = kcode & 0x03; + sum = block + 9 + ((dt_l == 3) | (dt_l & 0x02)); + sum_h = sum >> 1; + sum_l = sum & 0x01; + detune = pg_detune[(sum_l << 2) | note] >> (9 - sum_h); + } + if (dt & 0x04) + { + basefreq -= detune; + } + else + { + basefreq += detune; + } + basefreq &= 0x1ffff; + if (multi) + { + inc = basefreq * multi; + } + else + { + inc = basefreq >> 1; + } + inc &= 0xfffff; + chip->pg_inc[slot] = inc; +} + +static inline void OPM_PhaseGenerate(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 27) % 32; + chip->pg_reset_latch[slot] = chip->pg_reset[slot]; + slot = (chip->cycles + 25) % 32; + /* Mask increment */ + if (chip->pg_reset_latch[slot]) + { + chip->pg_inc[slot] = 0; + } + /* Phase step */ + slot = (chip->cycles + 24) % 32; + if (chip->pg_reset_latch[slot] || chip->mode_test[3]) + { + chip->pg_phase[slot] = 0; + } + chip->pg_phase[slot] += chip->pg_inc[slot]; + chip->pg_phase[slot] &= 0xfffff; +} + +static inline void OPM_PhaseDebug(opm_t *chip) +{ + chip->pg_serial >>= 1; + if (chip->cycles == 5) + { + chip->pg_serial |= (chip->pg_phase[29] & 0x3ff); + } +} + +static inline void OPM_KeyOn1(opm_t *chip) +{ + uint32_t cycles = (chip->cycles + 1) % 32; + chip->kon_chanmatch = 0; + if (chip->mode_kon_channel + 24 == cycles) + { + chip->kon_chanmatch = 1; + } +} + +static inline void OPM_KeyOn2(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 8) % 32; + if (chip->kon_chanmatch) + { + chip->mode_kon[(slot + 0) % 32] = chip->mode_kon_operator[0]; + chip->mode_kon[(slot + 8) % 32] = chip->mode_kon_operator[2]; + chip->mode_kon[(slot + 16) % 32] = chip->mode_kon_operator[1]; + chip->mode_kon[(slot + 24) % 32] = chip->mode_kon_operator[3]; + } +} + +static inline void OPM_EnvelopePhase1(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 2) % 32; + uint32_t kon = chip->mode_kon[slot] | chip->kon_csm; + uint32_t konevent = !chip->kon[slot] && kon; + if (konevent) + { + chip->eg_state[slot] = eg_num_attack; + } + + chip->kon2[slot] = chip->kon[slot]; + chip->kon[slot] = kon; +} + +static inline void OPM_EnvelopePhase2(opm_t *chip) +{ + uint32_t slot = chip->cycles; + uint32_t chan = slot % 8; + uint8_t rate = 0, ksv, zr, ams; + switch (chip->eg_state[slot]) + { + case eg_num_attack: + rate = chip->sl_ar[slot]; + break; + case eg_num_decay: + rate = chip->sl_d1r[slot]; + break; + case eg_num_sustain: + rate = chip->sl_d2r[slot]; + break; + case eg_num_release: + rate = chip->sl_rr[slot] * 2 + 1; + break; + default: + break; + } + if (chip->ic) + { + rate = 31; + } + + zr = rate == 0; + + ksv = chip->pg_kcode[slot] >> (chip->sl_ks[slot] ^ 3); + if (chip->sl_ks[slot] == 0 && zr) + { + ksv &= ~3; + } + rate = rate * 2 + ksv; + if (rate & 64) + { + rate = 63; + } + + chip->eg_tl[2] = chip->eg_tl[1]; + chip->eg_tl[1] = chip->eg_tl[0]; + chip->eg_tl[0] = chip->sl_tl[slot]; + chip->eg_sl[1] = chip->eg_sl[0]; + chip->eg_sl[0] = chip->sl_d1l[slot]; + if (chip->sl_d1l[slot] == 15) + { + chip->eg_sl[0] = 31; + } + chip->eg_zr[1] = chip->eg_zr[0]; + chip->eg_zr[0] = zr; + chip->eg_rate[1] = chip->eg_rate[0]; + chip->eg_rate[0] = rate; + chip->eg_ratemax[1] = chip->eg_ratemax[0]; + chip->eg_ratemax[0] = (rate >> 1) == 31; + ams = chip->sl_am_e[slot] ? chip->ch_ams[chan] : 0; + switch (ams) + { + default: + case 0: + chip->eg_am = 0; + break; + case 1: + chip->eg_am = chip->lfo_am_lock << 0; + break; + case 2: + chip->eg_am = chip->lfo_am_lock << 1; + break; + case 3: + chip->eg_am = chip->lfo_am_lock << 2; + break; + } +} + +static inline void OPM_EnvelopePhase3(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 31) % 32; + chip->eg_shift = (chip->eg_timershift_lock + (chip->eg_rate[0] >> 2)) & 15; + chip->eg_inchi = eg_stephi[chip->eg_rate[0] & 3][chip->eg_timer_lock & 3]; + + chip->eg_outtemp[1] = chip->eg_outtemp[0]; + chip->eg_outtemp[0] = chip->eg_level[slot] + chip->eg_am; + if (chip->eg_outtemp[0] & 1024) + { + chip->eg_outtemp[0] = 1023; + } +} + +static inline void OPM_EnvelopePhase4(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 30) % 32; + uint8_t inc = 0; + uint8_t kon, eg_off, eg_zero, slreach; + if (chip->eg_clock & 2) + { + if (chip->eg_rate[1] >= 48) + { + inc = chip->eg_inchi + (chip->eg_rate[1] >> 2) - 11; + if (inc > 4) + { + inc = 4; + } + } + else if (!chip->eg_zr[1]) + { + switch (chip->eg_shift) + { + case 12: + inc = chip->eg_rate[1] != 0; + break; + case 13: + inc = (chip->eg_rate[1] >> 1) & 1; + break; + case 14: + inc = chip->eg_rate[1] & 1; + break; + } + } + } + chip->eg_inc = inc; + + kon = chip->kon[slot] && !chip->kon2[slot]; + chip->pg_reset[slot] = kon; + chip->eg_instantattack = chip->eg_ratemax[1] && (kon || !chip->eg_ratemax[1]); + + eg_off = (chip->eg_level[slot] & 0x3f0) == 0x3f0; + slreach = (chip->eg_level[slot] >> 5) == chip->eg_sl[1]; + eg_zero = chip->eg_level[slot] == 0; + + chip->eg_mute = eg_off && chip->eg_state[slot] != eg_num_attack && !kon; + chip->eg_inclinear = 0; + if (!kon && !eg_off) + { + switch (chip->eg_state[slot]) + { + case eg_num_decay: + if (!slreach) + chip->eg_inclinear = 1; + break; + case eg_num_sustain: + case eg_num_release: + chip->eg_inclinear = 1; + break; + } + } + chip->eg_incattack = chip->eg_state[slot] == eg_num_attack && !chip->eg_ratemax[1] && chip->kon[slot] && !eg_zero; + + + // Update state + if (kon) + { + chip->eg_state[slot] = eg_num_attack; + } + else if (!chip->kon[slot]) + { + chip->eg_state[slot] = eg_num_release; + } + else + { + switch (chip->eg_state[slot]) + { + case eg_num_attack: + if (eg_zero) + { + chip->eg_state[slot] = eg_num_decay; + } + break; + case eg_num_decay: + if (eg_off) + { + chip->eg_state[slot] = eg_num_release; + } + else if (slreach) + { + chip->eg_state[slot] = eg_num_sustain; + } + break; + case eg_num_sustain: + if (eg_off) + { + chip->eg_state[slot] = eg_num_release; + } + break; + case eg_num_release: + break; + } + } + + if (chip->ic) + { + chip->eg_state[slot] = eg_num_release; + } +} + +static inline void OPM_EnvelopePhase5(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 29) % 32; + uint32_t level = chip->eg_level[slot]; + uint32_t step = 0; + if (chip->eg_instantattack) + { + level = 0; + } + if (chip->eg_mute || chip->ic) + { + level = 0x3ff; + } + if (chip->eg_inc) + { + if (chip->eg_inclinear) + { + step |= 1 << (chip->eg_inc - 1); + } + if (chip->eg_incattack) + { + step |= ((~(int32_t)chip->eg_level[slot]) << chip->eg_inc) >> 5; + } + } + level += step; + chip->eg_level[slot] = (uint16_t)level; + + chip->eg_out[0] = chip->eg_outtemp[1] + (chip->eg_tl[2] << 3); + if (chip->eg_out[0] & 1024) + { + chip->eg_out[0] = 1023; + } + + if (chip->eg_test) + { + chip->eg_out[0] = 0; + } + + chip->eg_test = chip->mode_test[5]; +} + +static inline void OPM_EnvelopePhase6(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 28) % 32; + chip->eg_serial_bit = (chip->eg_serial >> 9) & 1; + if (chip->cycles == 3) + { + chip->eg_serial = chip->eg_out[0] ^ 1023; + } + else + { + chip->eg_serial <<= 1; + } + + chip->eg_out[1] = chip->eg_out[0]; +} + +static void OPM_EnvelopeClock(opm_t *chip) +{ + chip->eg_clock <<= 1; + if ((chip->eg_clockcnt & 2) != 0 || chip->mode_test[0]) + { + chip->eg_clock |= 1; + } + if (chip->ic || (chip->cycles == 31 && (chip->eg_clockcnt & 2) != 0)) + { + chip->eg_clockcnt = 0; + } + else if (chip->cycles == 31) + { + chip->eg_clockcnt++; + } +} + +static inline void OPM_EnvelopeTimer(opm_t *chip) +{ + uint32_t cycle = (chip->cycles + 31) % 16; + uint32_t cycle2; + uint8_t inc = ((chip->cycles + 31) % 32) < 16 && (chip->eg_clock & 1) != 0 && (cycle == 0 || chip->eg_timercarry); + uint8_t timerbit = (chip->eg_timer >> cycle) & 1; + uint8_t sum = timerbit + inc; + uint8_t sum0 = (sum & 1) && !chip->ic; + chip->eg_timercarry = sum >> 1; + chip->eg_timer = (chip->eg_timer & (~(1 << cycle))) | (sum0 << cycle); + + cycle2 = (chip->cycles + 30) % 16; + + chip->eg_timer2 <<= 1; + if ((chip->eg_timer & (1 << cycle2)) != 0 && !chip->eg_timerbstop) + { + chip->eg_timer2 |= 1; + } + + if (chip->eg_timer & (1 << cycle2)) + { + chip->eg_timerbstop = 1; + } + + if (cycle == 0 || chip->ic2) + { + chip->eg_timerbstop = 0; + } + + if (chip->cycles == 1 && (chip->eg_clock & 1) != 0) + { + chip->eg_timershift_lock = 0; + if (chip->eg_timer2 & (8 + 32 + 128 + 512 + 2048 + 8192 + 32768)) + { + chip->eg_timershift_lock |= 1; + } + if (chip->eg_timer2 & (4 + 32 + 64 + 512 + 1024 + 8192 + 16384)) + { + chip->eg_timershift_lock |= 2; + } + if (chip->eg_timer2 & (4 + 8 + 16 + 512 + 1024 + 2048 + 4096)) + { + chip->eg_timershift_lock |= 4; + } + if (chip->eg_timer2 & (4 + 8 + 16 + 32 + 64 + 128 + 256)) + { + chip->eg_timershift_lock |= 8; + } + chip->eg_timer_lock = chip->eg_timer; + } +} + +static inline void OPM_OperatorPhase1(opm_t *chip) +{ + uint32_t slot = chip->cycles; + int16_t mod = chip->op_mod[2]; + chip->op_phase_in = chip->pg_phase[slot] >> 10; + if (chip->op_fbshift & 8) + { + if (chip->op_fb[1] == 0) + { + mod = 0; + } + else + { + mod = mod >> (9 - chip->op_fb[1]); + } + } + chip->op_mod_in = mod; +} + +static inline void OPM_OperatorPhase2(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 31) % 32; + chip->op_phase = (chip->op_phase_in + chip->op_mod_in) & 1023; +} + +static inline void OPM_OperatorPhase3(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 30) % 32; + uint16_t phase = chip->op_phase & 255; + if (chip->op_phase & 256) + { + phase ^= 255; + } + chip->op_logsin[0] = logsinrom[phase]; + chip->op_sign <<= 1; + chip->op_sign |= (chip->op_phase >> 9) & 1; +} + +static inline void OPM_OperatorPhase4(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 29) % 32; + chip->op_logsin[1] = chip->op_logsin[0]; +} + +static inline void OPM_OperatorPhase5(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 28) % 32; + chip->op_logsin[2] = chip->op_logsin[1]; +} + +static inline void OPM_OperatorPhase6(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 27) % 32; + chip->op_atten = chip->op_logsin[2] + (chip->eg_out[1] << 2); + if (chip->op_atten & 4096) + { + chip->op_atten = 4095; + } +} + +static inline void OPM_OperatorPhase7(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 26) % 32; + chip->op_exp[0] = exprom[chip->op_atten & 255]; + chip->op_pow[0] = chip->op_atten >> 8; +} + +static inline void OPM_OperatorPhase8(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 25) % 32; + chip->op_exp[1] = chip->op_exp[0]; + chip->op_pow[1] = chip->op_pow[0]; +} + +static inline void OPM_OperatorPhase9(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 24) % 32; + int16_t out = (chip->op_exp[1] << 2) >> (chip->op_pow[1]); + if (chip->op_sign & 32) + { + out = -out; + } + chip->op_out[0] = out; +} + +static inline void OPM_OperatorPhase10(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 23) % 32; + chip->op_out[1] = chip->op_out[0]; +} + +static inline void OPM_OperatorPhase11(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 22) % 32; + chip->op_out[2] = chip->op_out[1]; +} + +static inline void OPM_OperatorPhase12(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 21) % 32; + chip->op_out[3] = chip->op_out[2]; +} + +static inline void OPM_OperatorPhase13(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 20) % 32; + chip->op_out[4] = chip->op_out[3]; + chip->op_connect = chip->ch_connect[slot % 8]; +} + +static inline void OPM_OperatorPhase14(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 19) % 32; + chip->op_mix = chip->op_out[5] = chip->op_out[4]; + chip->op_fbupdate = (chip->op_counter == 0); + chip->op_c1update = (chip->op_counter == 2); + chip->op_fbshift <<= 1; + chip->op_fbshift |= (chip->op_counter == 2); + + chip->op_modtable[0] = fm_algorithm[(chip->op_counter+2)%4][0][chip->op_connect]; + chip->op_modtable[1] = fm_algorithm[(chip->op_counter+2)%4][1][chip->op_connect]; + chip->op_modtable[2] = fm_algorithm[(chip->op_counter+2)%4][2][chip->op_connect]; + chip->op_modtable[3] = fm_algorithm[(chip->op_counter+2)%4][3][chip->op_connect]; + chip->op_modtable[4] = fm_algorithm[(chip->op_counter+2)%4][4][chip->op_connect]; + chip->op_mixl = fm_algorithm[chip->op_counter][5][chip->op_connect] && (chip->ch_rl[slot % 8] & 1) != 0; + chip->op_mixr = fm_algorithm[chip->op_counter][5][chip->op_connect] && (chip->ch_rl[slot % 8] & 2) != 0; +} + +static inline void OPM_OperatorPhase15(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 18) % 32; + int16_t mod, mod1 = 0, mod2 = 0; + if (chip->op_modtable[0]) + { + mod2 |= chip->op_m1[slot % 8][0]; + } + if (chip->op_modtable[1]) + { + mod1 |= chip->op_m1[slot % 8][1]; + } + if (chip->op_modtable[2]) + { + mod1 |= chip->op_c1[slot % 8]; + } + if (chip->op_modtable[3]) + { + mod2 |= chip->op_out[5]; + } + if (chip->op_modtable[4]) + { + mod1 |= chip->op_out[5]; + } + mod = (mod1 + mod2) >> 1; + chip->op_mod[0] = mod; + if (chip->op_fbupdate) + { + chip->op_m1[slot % 8][1] = chip->op_m1[slot % 8][0]; + chip->op_m1[slot % 8][0] = chip->op_out[5]; + } + if (chip->op_c1update) + { + chip->op_c1[slot % 8] = chip->op_out[5]; + } +} + +static inline void OPM_OperatorPhase16(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 17) % 32; + // hack + chip->op_mod[2] = chip->op_mod[1]; + chip->op_fb[1] = chip->op_fb[0]; + + chip->op_mod[1] = chip->op_mod[0]; + chip->op_fb[0] = chip->ch_fb[slot % 8]; +} + +static inline void OPM_OperatorCounter(opm_t *chip) +{ + if ((chip->cycles % 8) == 4) + { + chip->op_counter++; + } + if (chip->cycles == 12) + { + chip->op_counter = 0; + } +} + +static inline void OPM_Mixer2(opm_t *chip) +{ + uint32_t cycles = (chip->cycles + 30) % 32; + uint8_t bit; + uint8_t top, ex; + if (cycles < 16) + { + bit = chip->mix_serial[0] & 1; + } + else + { + bit = chip->mix_serial[1] & 1; + } + if (chip->cycles % 16 == 1) + { + chip->mix_sign_lock = bit ^ 1; + chip->mix_top_bits_lock = (chip->mix_bits >> 15) & 63; + } + chip->mix_bits >>= 1; + chip->mix_bits |= bit << 20; + if (chip->cycles % 16 == 10) + { + top = chip->mix_top_bits_lock; + if (chip->mix_sign_lock) + { + top ^= 63; + } + if (top & 32) + { + ex = 7; + } + else if (top & 16) + { + ex = 6; + } + else if (top & 8) + { + ex = 5; + } + else if (top & 4) + { + ex = 4; + } + else if (top & 2) + { + ex = 3; + } + else if (top & 1) + { + ex = 2; + } + else + { + ex = 1; + } + chip->mix_sign_lock2 = chip->mix_sign_lock; + chip->mix_exp_lock = ex; + } + chip->mix_out_bit <<= 1; + switch ((chip->cycles + 1) % 16) + { + case 0: + chip->mix_out_bit |= chip->mix_sign_lock2 ^ 1; + break; + case 1: + chip->mix_out_bit |= (chip->mix_exp_lock >> 0) & 1; + break; + case 2: + chip->mix_out_bit |= (chip->mix_exp_lock >> 1) & 1; + break; + case 3: + chip->mix_out_bit |= (chip->mix_exp_lock >> 2) & 1; + break; + default: + if (chip->mix_exp_lock) + { + chip->mix_out_bit |= (chip->mix_bits >> (chip->mix_exp_lock - 1)) & 1; + } + break; + } +} + +static inline void OPM_Output(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 27) % 32; + chip->smp_so = (chip->mix_out_bit & 4) != 0; + chip->smp_sh1 = (slot & 24) == 8 && !chip->ic; + chip->smp_sh2 = (slot & 24) == 24 && !chip->ic; +} + +static inline void OPM_DAC(opm_t *chip) +{ + int32_t exp, mant; + if (chip->dac_osh1 && !chip->smp_sh1) + { + exp = (chip->dac_bits >> 10) & 7; + mant = (chip->dac_bits >> 0) & 1023; + mant -= 512; + chip->dac_output[1] = (mant << exp) >> 1; + } + if (chip->dac_osh2 && !chip->smp_sh2) + { + exp = (chip->dac_bits >> 10) & 7; + mant = (chip->dac_bits >> 0) & 1023; + mant -= 512; + chip->dac_output[0] = (mant << exp) >> 1; + } + chip->dac_bits >>= 1; + chip->dac_bits |= chip->smp_so << 12; + chip->dac_osh1 = chip->smp_sh1; + chip->dac_osh2 = chip->smp_sh2; +} + +static inline void OPM_Mixer(opm_t *chip) +{ + uint32_t slot = (chip->cycles + 18) % 32; + uint32_t channel = (slot % 8); + // Right channel + chip->mix_serial[1] >>= 1; + if (chip->cycles == 13) + { + chip->mix_serial[1] |= (chip->mix[1] & 1023) << 4; + } + if (chip->cycles == 14) + { + chip->mix_serial[1] |= ((chip->mix2[1] >> 10) & 31) << 13; + chip->mix_serial[1] |= (((chip->mix2[1] >> 17) & 1) ^ 1) << 18; + chip->mix_clamp_low[1] = 0; + chip->mix_clamp_high[1] = 0; + switch ((chip->mix2[1]>>15) & 7) + { + case 0: + default: + break; + case 1: + chip->mix_clamp_high[1] = 1; + break; + case 2: + chip->mix_clamp_high[1] = 1; + break; + case 3: + chip->mix_clamp_high[1] = 1; + break; + case 4: + chip->mix_clamp_low[1] = 1; + break; + case 5: + chip->mix_clamp_low[1] = 1; + break; + case 6: + chip->mix_clamp_low[1] = 1; + break; + case 7: + break; + } + } + if (chip->mix_clamp_low[1]) + { + chip->mix_serial[1] &= ~2; + } + if (chip->mix_clamp_high[1]) + { + chip->mix_serial[1] |= 2; + } + // Left channel + chip->mix_serial[0] >>= 1; + if (chip->cycles == 29) + { + chip->mix_serial[0] |= (chip->mix[0] & 1023) << 4; + } + if (chip->cycles == 30) + { + chip->mix_serial[0] |= ((chip->mix2[0] >> 10) & 31) << 13; + chip->mix_serial[0] |= (((chip->mix2[0] >> 17) & 1) ^ 1) << 18; + chip->mix_clamp_low[0] = 0; + chip->mix_clamp_high[0] = 0; + switch ((chip->mix2[0]>>15) & 7) + { + case 0: + default: + break; + case 1: + chip->mix_clamp_high[0] = 1; + break; + case 2: + chip->mix_clamp_high[0] = 1; + break; + case 3: + chip->mix_clamp_high[0] = 1; + break; + case 4: + chip->mix_clamp_low[0] = 1; + break; + case 5: + chip->mix_clamp_low[0] = 1; + break; + case 6: + chip->mix_clamp_low[0] = 1; + break; + case 7: + break; + } + } + if (chip->mix_clamp_low[0]) + { + chip->mix_serial[0] &= ~2; + } + if (chip->mix_clamp_high[0]) + { + chip->mix_serial[0] |= 2; + } + chip->mix2[0] = chip->mix[0]; + chip->mix2[1] = chip->mix[1]; + if (chip->cycles == 13) + { + chip->mix[1] = 0; + } + if (chip->cycles == 29) + { + chip->mix[0] = 0; + } + chip->mix[0] += chip->op_mix * chip->op_mixl; + chip->mix[1] += chip->op_mix * chip->op_mixr; +} + +static inline void OPM_Noise(opm_t *chip) +{ + uint8_t w1 = !chip->ic && !chip->noise_update; + uint8_t xr = ((chip->noise_lfsr >> 2) & 1) ^ chip->noise_temp; + uint8_t w2t = (chip->noise_lfsr & 0xffff) == 0xffff && chip->noise_temp == 0; + uint8_t w2 = !w2t && !xr; + uint8_t w3 = !chip->ic && !w1 && !w2; + uint8_t w4 = ((chip->noise_lfsr & 1) == 0 || !w1) && !w3; + if (!w1) + { + chip->noise_temp = (chip->noise_lfsr & 1) == 0; + } + chip->noise_lfsr >>= 1; + chip->noise_lfsr |= w4 << 15; +} + +static inline void OPM_NoiseTimer(opm_t *chip) +{ + uint32_t timer = chip->noise_timer; + + chip->noise_update = chip->noise_timer_of; + + if (chip->cycles % 16 == 15) + { + timer++; + timer &= 31; + } + if (chip->ic || (chip->noise_timer_of && (chip->cycles % 16 == 15))) + { + timer = 0; + } + + chip->noise_timer_of = chip->noise_timer == (chip->noise_freq ^ 31); + chip->noise_timer = timer; +} + +static inline void OPM_DoTimerA(opm_t *chip) +{ + uint16_t value = chip->timer_a_val; + value += chip->timer_a_inc; + chip->timer_a_of = (value >> 10) & 1; + if (chip->timer_a_do_reset) + { + value = 0; + } + if (chip->timer_a_do_load) + { + value = chip->timer_a_reg; + } + + chip->timer_a_val = value & 1023; +} + +static inline void OPM_DoTimerA2(opm_t *chip) +{ + if (chip->cycles == 1) + { + chip->timer_a_load = chip->timer_loada; + } + chip->timer_a_inc = chip->mode_test[2] || (chip->timer_a_load && chip->cycles == 0); + chip->timer_a_do_load = chip->timer_a_of || (chip->timer_a_load && chip->timer_a_temp); + chip->timer_a_do_reset = chip->timer_a_temp; + chip->timer_a_temp = !chip->timer_a_load; + if (chip->timer_reseta || chip->ic) + { + chip->timer_a_status = 0; + } + else + { + chip->timer_a_status |= chip->timer_irqa && chip->timer_a_of; + } + chip->timer_reseta = 0; +} + +static inline void OPM_DoTimerB(opm_t *chip) +{ + uint16_t value = chip->timer_b_val; + value += chip->timer_b_inc; + chip->timer_b_of = (value >> 8) & 1; + if (chip->timer_b_do_reset) + { + value = 0; + } + if (chip->timer_b_do_load) + { + value = chip->timer_b_reg; + } + + chip->timer_b_val = value & 255; + + if (chip->cycles == 0) + { + chip->timer_b_sub++; + } + + chip->timer_b_sub_of = (chip->timer_b_sub >> 4) & 1; + chip->timer_b_sub &= 15; + if (chip->ic) + { + chip->timer_b_sub = 0; + } +} + +static inline void OPM_DoTimerB2(opm_t *chip) +{ + chip->timer_b_inc = chip->mode_test[2] || (chip->timer_loadb && chip->timer_b_sub_of); + chip->timer_b_do_load = chip->timer_b_of || (chip->timer_loadb && chip->timer_b_temp); + chip->timer_b_do_reset = chip->timer_b_temp; + chip->timer_b_temp = !chip->timer_loadb; + if (chip->timer_resetb || chip->ic) + { + chip->timer_b_status = 0; + } + else + { + chip->timer_b_status |= chip->timer_irqb && chip->timer_b_of; + } + chip->timer_resetb = 0; +} + +static inline void OPM_DoTimerIRQ(opm_t *chip) +{ + chip->timer_irq = chip->timer_a_status || chip->timer_b_status; +} + +static inline void OPM_DoLFOMult(opm_t *chip) +{ + uint8_t ampm_sel = (chip->lfo_bit_counter & 8) != 0; + uint8_t dp = ampm_sel ? chip->lfo_pmd : chip->lfo_amd; + uint8_t bit = 0, b1, b2; + uint8_t sum; + + chip->lfo_out2_b = chip->lfo_out2; + + switch (chip->lfo_bit_counter & 7) + { + case 0: + bit = (dp & 64) != 0 && (chip->lfo_out1 & 64) == 0; + break; + case 1: + bit = (dp & 32) != 0 && (chip->lfo_out1 & 32) == 0; + break; + case 2: + bit = (dp & 16) != 0 && (chip->lfo_out1 & 16) == 0; + break; + case 3: + bit = (dp & 8) != 0 && (chip->lfo_out1 & 8) == 0; + break; + case 4: + bit = (dp & 4) != 0 && (chip->lfo_out1 & 4) == 0; + break; + case 5: + bit = (dp & 2) != 0 && (chip->lfo_out1 & 2) == 0; + break; + case 6: + bit = (dp & 1) != 0 && (chip->lfo_out1 & 1) == 0; + break; + } + + b1 = (chip->lfo_out2 & 1) != 0; + if ((chip->lfo_bit_counter & 7) == 0) + { + b1 = 0; + } + b2 = chip->lfo_mult_carry; + if (chip->cycles % 16 == 15) + { + b2 = 0; + } + sum = bit + b1 + b2; + chip->lfo_out2 >>= 1; + chip->lfo_out2 |= (sum & 1) << 15; + chip->lfo_mult_carry = sum >> 1; +} + +static inline void OPM_DoLFO1(opm_t *chip) +{ + uint16_t counter2 = chip->lfo_counter2; + uint8_t of_old = chip->lfo_counter2_of; + uint8_t lfo_bit, noise, sum, carry, w[10]; + uint8_t lfo_pm_sign; + uint8_t ampm_sel = (chip->lfo_bit_counter & 8) != 0; + counter2 += (chip->lfo_counter1_of1 & 2) != 0 || chip->mode_test[3]; + chip->lfo_counter2_of = (counter2 >> 15) & 1; + if (chip->ic) + { + counter2 = 0; + } + if (chip->lfo_counter2_load) + { + counter2 = lfo_counter2_table[chip->lfo_freq_hi]; + } + chip->lfo_counter2 = counter2 & 32767; + chip->lfo_counter2_load = chip->lfo_frq_update || of_old; + chip->lfo_frq_update = 0; + if ((chip->cycles % 16) == 12) + { + chip->lfo_counter1++; + } + chip->lfo_counter1_of1 <<= 1; + chip->lfo_counter1_of1 |= (chip->lfo_counter1 >> 4) & 1; + chip->lfo_counter1 &= 15; + if (chip->ic) + { + chip->lfo_counter1 = 0; + } + + if ((chip->cycles & 15) == 5) + { + chip->lfo_counter2_of_lock2 = chip->lfo_counter2_of_lock; + } + + chip->lfo_counter3 += chip->lfo_counter3_clock; + if (chip->ic) + { + chip->lfo_counter3 = 0; + } + + chip->lfo_counter3_clock = (chip->cycles & 15) == 13 && chip->lfo_counter2_of_lock2; + + if ((chip->cycles & 15) == 15) + { + chip->lfo_trig_sign = (chip->lfo_val & 0x80) != 0; + chip->lfo_saw_sign = (chip->lfo_val & 0x100) != 0; + } + + lfo_pm_sign = chip->lfo_wave == 2 ? chip->lfo_trig_sign : chip->lfo_saw_sign; + + w[5] = ampm_sel ? chip->lfo_saw_sign : (chip->lfo_wave != 2 || !chip->lfo_trig_sign); + + w[1] = !chip->lfo_clock || chip->lfo_wave == 3 || (chip->cycles & 15) != 15; + w[2] = chip->lfo_wave == 2 && !w[1]; + w[4] = chip->lfo_clock_lock && chip->lfo_wave == 3; + w[3] = !chip->ic && !chip->mode_test[1] && !w[4] && (chip->lfo_val & 0x8000) != 0; + + w[7] = ((chip->cycles + 1) % 16) < 8; + + w[6] = w[5] ^ w[3]; + + w[9] = ampm_sel ? ((chip->cycles % 16) == 6) : !chip->lfo_saw_sign; + + w[8] = chip->lfo_wave == 1 ? w[9] : w[6]; + + w[8] &= w[7]; + + chip->lfo_out1 <<= 1; + chip->lfo_out1 |= !w[8]; + + carry = !w[1] || ((chip->cycles & 15) != 15 && chip->lfo_val_carry != 0 && chip->lfo_wave != 3); + sum = carry + w[2] + w[3]; + noise = chip->lfo_clock_lock && (chip->noise_lfsr & 1) != 0; + lfo_bit = sum & 1; + lfo_bit |= (chip->lfo_wave == 3) && noise; + chip->lfo_val_carry = sum >> 1; + chip->lfo_val <<= 1; + chip->lfo_val |= lfo_bit; + + + if (chip->cycles % 16 == 15 && (chip->lfo_bit_counter & 7) == 7) + { + if (ampm_sel) + { + chip->lfo_pm_lock = (chip->lfo_out2_b >> 8) & 255; + chip->lfo_pm_lock ^= lfo_pm_sign << 7; + } + else + { + chip->lfo_am_lock = (chip->lfo_out2_b >> 8) & 255; + } + } + + if ((chip->cycles & 15) == 14) + { + chip->lfo_bit_counter++; + } + if ((chip->cycles & 15) != 12 && chip->lfo_counter1_of2) + { + chip->lfo_bit_counter = 0; + } + chip->lfo_counter1_of2 = chip->lfo_counter1 == 2; +} + +static inline void OPM_DoLFO2(opm_t *chip) +{ + chip->lfo_clock_test = chip->lfo_clock; + chip->lfo_clock = (chip->lfo_counter2_of || chip->lfo_test || chip->lfo_counter3_step); + if ((chip->cycles & 15) == 14) + { + chip->lfo_counter2_of_lock = chip->lfo_counter2_of; + chip->lfo_clock_lock = chip->lfo_clock; + } + chip->lfo_counter3_step = 0; + if (chip->lfo_counter3_clock) + { + if ((chip->lfo_counter3 & 1) == 0) + { + chip->lfo_counter3_step = (chip->lfo_freq_lo & 8) != 0; + } + else if ((chip->lfo_counter3 & 2) == 0) + { + chip->lfo_counter3_step = (chip->lfo_freq_lo & 4) != 0; + } + else if ((chip->lfo_counter3 & 4) == 0) + { + chip->lfo_counter3_step = (chip->lfo_freq_lo & 2) != 0; + } + else if ((chip->lfo_counter3 & 8) == 0) + { + chip->lfo_counter3_step = (chip->lfo_freq_lo & 1) != 0; + } + } + chip->lfo_test = chip->mode_test[2]; +} + +static inline void OPM_CSM(opm_t *chip) +{ + chip->kon_csm = chip->kon_csm_lock; + if (chip->cycles == 1) + { + chip->kon_csm_lock = chip->timer_a_do_load && chip->mode_csm; + } +} + +static inline void OPM_NoiseChannel(opm_t *chip) +{ + chip->nc_active |= chip->eg_serial_bit & 1; + if (chip->cycles == 13) + { + chip->nc_active = 0; + } + chip->nc_out <<= 1; + chip->nc_out |= chip->nc_sign ^ chip->eg_serial_bit; + chip->nc_sign = !chip->nc_sign_lock; + if (chip->cycles == 12) + { + chip->nc_active_lock = chip->nc_active; + chip->nc_sign_lock2 = chip->nc_active_lock && !chip->nc_sign_lock; + chip->nc_sign_lock = (chip->noise_lfsr & 1); + + if (chip->noise_en) + { + if (chip->nc_sign_lock2) + { + chip->op_mix = ((chip->nc_out & ~1) << 2) | -4089; + } + else + { + chip->op_mix = ((chip->nc_out & ~1) << 2); + } + } + } +} + +static inline void OPM_DoIO(opm_t *chip) +{ + // Busy + chip->write_busy_cnt += chip->write_busy; + chip->write_busy = (!(chip->write_busy_cnt >> 5) && chip->write_busy && !chip->ic) | chip->write_d_en; + chip->write_busy_cnt &= 0x1f; + if (chip->ic) + { + chip->write_busy_cnt = 0; + } + // Write signal check + chip->write_a_en = chip->write_a; + chip->write_d_en = chip->write_d; + chip->write_a = 0; + chip->write_d = 0; +} + +static inline void OPM_DoRegWrite(opm_t *chip) +{ + int32_t i; + uint32_t channel = chip->cycles % 8; + uint32_t slot = chip->cycles; + + // Register write + if (chip->reg_data_ready) + { + // Channel + if ((chip->reg_address & 0xe7) == (0x20 | channel)) + { + switch (chip->reg_address & 0x18) + { + case 0x00: // RL, FB, CONNECT + chip->ch_rl[channel] = chip->reg_data >> 6; + chip->ch_fb[channel] = (chip->reg_data >> 3) & 0x07; + chip->ch_connect[channel] = chip->reg_data & 0x07; + break; + case 0x08: // KC + chip->ch_kc[channel] = chip->reg_data & 0x7f; + break; + case 0x10: // KF + chip->ch_kf[channel] = chip->reg_data >> 2; + break; + case 0x18: // PMS, AMS + chip->ch_pms[channel] = (chip->reg_data >> 4) & 0x07; + chip->ch_ams[channel] = chip->reg_data & 0x03; + break; + default: + break; + } + } + // Slot + if ((chip->reg_address & 0x1f) == slot) + { + switch (chip->reg_address & 0xe0) + { + case 0x40: // DT1, MUL + chip->sl_dt1[slot] = (chip->reg_data >> 4) & 0x07; + chip->sl_mul[slot] = chip->reg_data & 0x0f; + break; + case 0x60: // TL + chip->sl_tl[slot] = chip->reg_data & 0x7f; + break; + case 0x80: // KS, AR + chip->sl_ks[slot] = chip->reg_data >> 6; + chip->sl_ar[slot] = chip->reg_data & 0x1f; + break; + case 0xa0: // AMS-EN, D1R + chip->sl_am_e[slot] = chip->reg_data >> 7; + chip->sl_d1r[slot] = chip->reg_data & 0x1f; + break; + case 0xc0: // DT2, D2R + chip->sl_dt2[slot] = chip->reg_data >> 6; + chip->sl_d2r[slot] = chip->reg_data & 0x1f; + break; + case 0xe0: // D1L, RR + chip->sl_d1l[slot] = chip->reg_data >> 4; + chip->sl_rr[slot] = chip->reg_data & 0x0f; + break; + default: + break; + } + } + } + + // Mode write + if (chip->write_d_en) + { + switch (chip->mode_address) + { + case 0x01: + for (i = 0; i < 8; i++) + { + chip->mode_test[i] = (chip->write_data >> i) & 0x01; + } + break; + case 0x08: + for (i = 0; i < 4; i++) + { + chip->mode_kon_operator[i] = (chip->write_data >> (i + 3)) & 0x01; + } + chip->mode_kon_channel = chip->write_data & 0x07; + break; + case 0x0f: + chip->noise_en = chip->write_data >> 7; + chip->noise_freq = chip->write_data & 0x1f; + break; + case 0x10: + chip->timer_a_reg &= 0x03; + chip->timer_a_reg |= chip->write_data << 2; + break; + case 0x11: + chip->timer_a_reg &= 0x3fc; + chip->timer_a_reg |= chip->write_data & 0x03; + break; + case 0x12: + chip->timer_b_reg = chip->write_data; + break; + case 0x14: + chip->mode_csm = (chip->write_data >> 7) & 1; + chip->timer_irqb = (chip->write_data >> 3) & 1; + chip->timer_irqa = (chip->write_data >> 2) & 1; + chip->timer_resetb = (chip->write_data >> 5) & 1; + chip->timer_reseta = (chip->write_data >> 4) & 1; + chip->timer_loadb = (chip->write_data >> 1) & 1; + chip->timer_loada = (chip->write_data >> 0) & 1; + break; + case 0x18: + chip->lfo_freq_hi = chip->write_data >> 4; + chip->lfo_freq_lo = chip->write_data & 0x0f; + chip->lfo_frq_update = 1; + break; + case 0x19: + if (chip->write_data & 0x80) + { + chip->lfo_pmd = chip->write_data & 0x7f; + } + else + { + chip->lfo_amd = chip->write_data; + } + break; + case 0x1b: + chip->lfo_wave = chip->write_data & 0x03; + chip->io_ct1 = (chip->write_data >> 6) & 0x01; + chip->io_ct2 = chip->write_data >> 7; + break; + } + } + + // Register data write + chip->reg_data_ready = chip->reg_data_ready && !chip->write_a_en; + if (chip->reg_address_ready && chip->write_d_en) + { + chip->reg_data = chip->write_data; + chip->reg_data_ready = 1; + } + + // Register address write + chip->reg_address_ready = chip->reg_address_ready && !chip->write_a_en; + if (chip->write_a_en && (chip->write_data & 0xe0) != 0) + { + chip->reg_address = chip->write_data; + chip->reg_address_ready = 1; + } + if (chip->write_a_en) + { + chip->mode_address = chip->write_data; + } +} + +static inline void OPM_DoIC(opm_t *chip) +{ + uint32_t channel = chip->cycles % 8; + uint32_t slot = chip->cycles; + if (chip->ic) + { + chip->ch_rl[channel] = 0; + chip->ch_fb[channel] = 0; + chip->ch_connect[channel] = 0; + chip->ch_kc[channel] = 0; + chip->ch_kf[channel] = 0; + chip->ch_pms[channel] = 0; + chip->ch_ams[channel] = 0; + + chip->sl_dt1[slot] = 0; + chip->sl_mul[slot] = 0; + chip->sl_tl[slot] = 0; + chip->sl_ks[slot] = 0; + chip->sl_ar[slot] = 0; + chip->sl_am_e[slot] = 0; + chip->sl_d1r[slot] = 0; + chip->sl_dt2[slot] = 0; + chip->sl_d2r[slot] = 0; + chip->sl_d1l[slot] = 0; + chip->sl_rr[slot] = 0; + + chip->timer_a_reg = 0; + chip->timer_b_reg = 0; + chip->timer_irqa = 0; + chip->timer_irqb = 0; + chip->timer_loada = 0; + chip->timer_loadb = 0; + chip->mode_csm = 0; + + chip->mode_test[0] = 0; + chip->mode_test[1] = 0; + chip->mode_test[2] = 0; + chip->mode_test[3] = 0; + chip->mode_test[4] = 0; + chip->mode_test[5] = 0; + chip->mode_test[6] = 0; + chip->mode_test[7] = 0; + chip->noise_en = 0; + chip->noise_freq = 0; + + chip->mode_kon_channel = 0; + chip->mode_kon_operator[0] = 0; + chip->mode_kon_operator[1] = 0; + chip->mode_kon_operator[2] = 0; + chip->mode_kon_operator[3] = 0; + chip->mode_kon[(slot + 8) % 32] = 0; + + chip->lfo_pmd = 0; + chip->lfo_amd = 0; + chip->lfo_wave = 0; + chip->lfo_freq_hi = 0; + chip->lfo_freq_lo = 0; + + chip->io_ct1 = 0; + chip->io_ct2 = 0; + + chip->reg_address = 0; + chip->reg_data = 0; + } + chip->ic2 = chip->ic; +} + +void OPM_Clock(opm_t *chip, int32_t *output, uint8_t *sh1, uint8_t *sh2, uint8_t *so) +{ + OPM_Mixer2(chip); + OPM_Mixer(chip); + + OPM_OperatorPhase16(chip); + OPM_OperatorPhase15(chip); + OPM_OperatorPhase14(chip); + OPM_OperatorPhase13(chip); + OPM_OperatorPhase12(chip); + OPM_OperatorPhase11(chip); + OPM_OperatorPhase10(chip); + OPM_OperatorPhase9(chip); + OPM_OperatorPhase8(chip); + OPM_OperatorPhase7(chip); + OPM_OperatorPhase6(chip); + OPM_OperatorPhase5(chip); + OPM_OperatorPhase4(chip); + OPM_OperatorPhase3(chip); + OPM_OperatorPhase2(chip); + OPM_OperatorPhase1(chip); + OPM_OperatorCounter(chip); + + OPM_EnvelopeTimer(chip); + OPM_EnvelopePhase6(chip); + OPM_EnvelopePhase5(chip); + OPM_EnvelopePhase4(chip); + OPM_EnvelopePhase3(chip); + OPM_EnvelopePhase2(chip); + OPM_EnvelopePhase1(chip); + + OPM_PhaseDebug(chip); + OPM_PhaseGenerate(chip); + OPM_PhaseCalcIncrement(chip); + OPM_PhaseCalcFNumBlock(chip); + + /*OPM_DoTimerIRQ(chip); + OPM_DoTimerA(chip); + OPM_DoTimerB(chip);*/ + OPM_DoLFOMult(chip); + OPM_DoLFO1(chip); + OPM_Noise(chip); + OPM_KeyOn2(chip); + OPM_DoRegWrite(chip); + OPM_EnvelopeClock(chip); + OPM_NoiseTimer(chip); + OPM_KeyOn1(chip); + OPM_DoIO(chip); + /*OPM_DoTimerA2(chip); + OPM_DoTimerB2(chip);*/ + OPM_DoLFO2(chip); + //OPM_CSM(chip); + OPM_NoiseChannel(chip); + OPM_Output(chip); + OPM_DAC(chip); + OPM_DoIC(chip); + if (sh1) + { + *sh1 = chip->smp_sh1; + } + if (sh2) + { + *sh2 = chip->smp_sh2; + } + if (so) + { + *so = chip->smp_so; + } + if (output) + { + output[0] = chip->dac_output[0]; + output[1] = chip->dac_output[1]; + } + chip->cycles = (chip->cycles + 1) % 32; +} + +void OPM_Write(opm_t *chip, uint32_t port, uint8_t data) +{ + chip->write_data = data; + if (chip->ic) + { + return; + } + if (port & 0x01) + { + chip->write_d = 1; + } + else + { + chip->write_a = 1; + } +} + +uint8_t OPM_Read(opm_t *chip, uint32_t port) +{ + uint16_t testdata; + if (chip->mode_test[6]) + { + testdata = chip->op_out[5] | ((chip->eg_serial_bit ^ 1) << 14) | ((chip->pg_serial & 1) << 15); + if (chip->mode_test[7]) + { + return testdata & 255; + } + else + { + return testdata >> 8; + } + } + return (chip->write_busy << 7) | (chip->timer_b_status << 1) | chip->timer_a_status; +} + +uint8_t OPM_ReadIRQ(opm_t *chip) +{ + return chip->timer_irq; +} + +uint8_t OPM_ReadCT1(opm_t *chip) +{ + if(chip->mode_test[3]) + { + return chip->lfo_clock_test; + } + return chip->io_ct1; +} + +uint8_t OPM_ReadCT2(opm_t *chip) +{ + return chip->io_ct2; +} + +void OPM_SetIC(opm_t *chip, uint8_t ic) +{ + if (chip->ic != ic) + { + chip->ic = ic; + if (!ic) + { + chip->cycles = 0; + } + } +} + +void OPM_Reset(opm_t *chip) +{ + uint32_t i; + memset(chip, 0, sizeof(opm_t)); + OPM_SetIC(chip, 1); + for (i = 0; i < 32 * 64; i++) + { + OPM_Clock(chip, NULL, NULL, NULL, NULL); + } + OPM_SetIC(chip, 0); +} diff --git a/extern/opm/opm.h b/extern/opm/opm.h new file mode 100644 index 000000000..fe5a1518b --- /dev/null +++ b/extern/opm/opm.h @@ -0,0 +1,269 @@ +/* Nuked OPM + * Copyright (C) 2020 Nuke.YKT + * + * This file is part of Nuked OPM. + * + * Nuked OPM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 + * of the License, or (at your option) any later version. + * + * Nuked OPM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Nuked OPM. If not, see . + * + * Nuked OPM emulator. + * Thanks: + * siliconpr0n.org(digshadow, John McMaster): + * YM2151 and other FM chip decaps and die shots. + * + * version: 0.9.2 beta + */ +#ifndef _OPM_H_ +#define _OPM_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint32_t cycles; + uint8_t ic; + uint8_t ic2; + // IO + uint8_t write_data; + uint8_t write_a; + uint8_t write_a_en; + uint8_t write_d; + uint8_t write_d_en; + uint8_t write_busy; + uint8_t write_busy_cnt; + uint8_t mode_address; + uint8_t io_ct1; + uint8_t io_ct2; + + // LFO + uint8_t lfo_am_lock; + uint8_t lfo_pm_lock; + uint8_t lfo_counter1; + uint8_t lfo_counter1_of1; + uint8_t lfo_counter1_of2; + uint16_t lfo_counter2; + uint8_t lfo_counter2_load; + uint8_t lfo_counter2_of; + uint8_t lfo_counter2_of_lock; + uint8_t lfo_counter2_of_lock2; + uint8_t lfo_counter3_clock; + uint16_t lfo_counter3; + uint8_t lfo_counter3_step; + uint8_t lfo_frq_update; + uint8_t lfo_clock; + uint8_t lfo_clock_lock; + uint8_t lfo_clock_test; + uint8_t lfo_test; + uint32_t lfo_val; + uint8_t lfo_val_carry; + uint32_t lfo_out1; + uint32_t lfo_out2; + uint32_t lfo_out2_b; + uint8_t lfo_mult_carry; + uint8_t lfo_trig_sign; + uint8_t lfo_saw_sign; + uint8_t lfo_bit_counter; + + // Env Gen + uint8_t eg_state[32]; + uint16_t eg_level[32]; + uint8_t eg_rate[2]; + uint8_t eg_sl[2]; + uint8_t eg_tl[3]; + uint8_t eg_zr[2]; + uint8_t eg_timershift_lock; + uint8_t eg_timer_lock; + uint8_t eg_inchi; + uint8_t eg_shift; + uint8_t eg_clock; + uint8_t eg_clockcnt; + uint8_t eg_clockquotinent; + uint8_t eg_inc; + uint8_t eg_ratemax[2]; + uint8_t eg_instantattack; + uint8_t eg_inclinear; + uint8_t eg_incattack; + uint8_t eg_mute; + uint16_t eg_outtemp[2]; + uint16_t eg_out[2]; + uint16_t eg_am; + uint8_t eg_ams[2]; + uint8_t eg_timercarry; + uint32_t eg_timer; + uint32_t eg_timer2; + uint8_t eg_timerbstop; + uint32_t eg_serial; + uint8_t eg_serial_bit; + uint8_t eg_test; + + + // Phase Gen + uint16_t pg_fnum[32]; + uint8_t pg_kcode[32]; + uint32_t pg_inc[32]; + uint32_t pg_phase[32]; + uint8_t pg_reset[32]; + uint8_t pg_reset_latch[32]; + uint32_t pg_serial; + + // Operator + uint16_t op_phase_in; + uint16_t op_mod_in; + uint16_t op_phase; + uint16_t op_logsin[3]; + uint16_t op_atten; + uint16_t op_exp[2]; + uint8_t op_pow[2]; + uint32_t op_sign; + int16_t op_out[6]; + uint32_t op_connect; + uint8_t op_counter; + uint8_t op_fbupdate; + uint8_t op_fbshift; + uint8_t op_c1update; + uint8_t op_modtable[5]; + int16_t op_m1[8][2]; + int16_t op_c1[8]; + int16_t op_mod[3]; + int16_t op_fb[2]; + uint8_t op_mixl; + uint8_t op_mixr; + + // Mixer + + int32_t mix[2]; + int32_t mix2[2]; + int32_t mix_op; + uint32_t mix_serial[2]; + uint32_t mix_bits; + uint32_t mix_top_bits_lock; + uint8_t mix_sign_lock; + uint8_t mix_sign_lock2; + uint8_t mix_exp_lock; + uint8_t mix_clamp_low[2]; + uint8_t mix_clamp_high[2]; + uint8_t mix_out_bit; + + // Output + uint8_t smp_so; + uint8_t smp_sh1; + uint8_t smp_sh2; + + // Noise + uint32_t noise_lfsr; + uint32_t noise_timer; + uint8_t noise_timer_of; + uint8_t noise_update; + uint8_t noise_temp; + + // Register set + uint8_t mode_test[8]; + uint8_t mode_kon_operator[4]; + uint8_t mode_kon_channel; + + uint8_t reg_address; + uint8_t reg_address_ready; + uint8_t reg_data; + uint8_t reg_data_ready; + + uint8_t ch_rl[8]; + uint8_t ch_fb[8]; + uint8_t ch_connect[8]; + uint8_t ch_kc[8]; + uint8_t ch_kf[8]; + uint8_t ch_pms[8]; + uint8_t ch_ams[8]; + + uint8_t sl_dt1[32]; + uint8_t sl_mul[32]; + uint8_t sl_tl[32]; + uint8_t sl_ks[32]; + uint8_t sl_ar[32]; + uint8_t sl_am_e[32]; + uint8_t sl_d1r[32]; + uint8_t sl_dt2[32]; + uint8_t sl_d2r[32]; + uint8_t sl_d1l[32]; + uint8_t sl_rr[32]; + + uint8_t noise_en; + uint8_t noise_freq; + + + // Timer + uint16_t timer_a_reg; + uint8_t timer_b_reg; + uint8_t timer_a_temp; + uint8_t timer_a_do_reset, timer_a_do_load; + uint8_t timer_a_inc; + uint16_t timer_a_val; + uint8_t timer_a_of; + uint8_t timer_a_load; + uint8_t timer_a_status; + + uint8_t timer_b_sub; + uint8_t timer_b_sub_of; + uint8_t timer_b_inc; + uint16_t timer_b_val; + uint8_t timer_b_of; + uint8_t timer_b_do_reset, timer_b_do_load; + uint8_t timer_b_temp; + uint8_t timer_b_status; + uint8_t timer_irq; + + uint8_t lfo_freq_hi; + uint8_t lfo_freq_lo; + uint8_t lfo_pmd; + uint8_t lfo_amd; + uint8_t lfo_wave; + + uint8_t timer_irqa, timer_irqb; + uint8_t timer_loada, timer_loadb; + uint8_t timer_reseta, timer_resetb; + uint8_t mode_csm; + + uint8_t nc_active, nc_active_lock, nc_sign, nc_sign_lock, nc_sign_lock2; + uint8_t nc_bit; + uint16_t nc_out; + int16_t op_mix; + + uint8_t kon_csm, kon_csm_lock; + uint8_t kon_do; + uint8_t kon_chanmatch; + uint8_t kon[32]; + uint8_t kon2[32]; + uint8_t mode_kon[32]; + + // DAC + uint8_t dac_osh1, dac_osh2; + uint16_t dac_bits; + int32_t dac_output[2]; +} opm_t; + +void OPM_Clock(opm_t *chip, int32_t *output, uint8_t *sh1, uint8_t *sh2, uint8_t *so); +void OPM_Write(opm_t *chip, uint32_t port, uint8_t data); +uint8_t OPM_Read(opm_t *chip, uint32_t port); +uint8_t OPM_ReadIRQ(opm_t *chip); +uint8_t OPM_ReadCT1(opm_t *chip); +uint8_t OPM_ReadCT2(opm_t *chip); +void OPM_SetIC(opm_t *chip, uint8_t ic); +void OPM_Reset(opm_t *chip); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 85706ed0a..605d9399d 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -49,9 +49,9 @@ void DivPlatformArcade::acquire(short* bufL, short* bufR, size_t start, size_t l } } - OPM_Clock(&fm,o,NULL,NULL,NULL); - OPM_Clock(&fm,o,NULL,NULL,NULL); - OPM_Clock(&fm,o,NULL,NULL,NULL); + OPM_Clock(&fm,NULL,NULL,NULL,NULL); + OPM_Clock(&fm,NULL,NULL,NULL,NULL); + OPM_Clock(&fm,NULL,NULL,NULL,NULL); OPM_Clock(&fm,o,NULL,NULL,NULL); pcmCycles+=31250; diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index fbfa9f772..23b162bee 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -2,7 +2,7 @@ #define _ARCADE_H #include "../dispatch.h" #include -#include "../../../extern/Nuked-OPM/opm.h" +#include "../../../extern/opm/opm.h" class DivPlatformArcade: public DivDispatch { protected: