From d1db9bdd2f3bee07f13e84fc1b4d464ef22b08a3 Mon Sep 17 00:00:00 2001 From: Harm Date: Sat, 8 Aug 2020 19:51:28 +0200 Subject: [PATCH] Open source it! --- .gitignore | 21 + LICENSE | 674 +++++++++++++++++++++ OpenSndVoyager/premake5.lua | 19 + OpenSndVoyager/src/OpenSndVoyager.cpp | 808 ++++++++++++++++++++++++++ OpenSndVoyager/src/OpenSndVoyager.h | 164 ++++++ OpenSndVoyager/src/OpenSndVoyager.rc | Bin 0 -> 5292 bytes OpenSndVoyager/src/resource.h | 15 + README.md | 12 +- appveyor.yml | 34 ++ build.ps1 | 3 + premake5.bat | 2 + premake5.exe | Bin 0 -> 1362432 bytes premake5.lua | 31 + 13 files changed, 1782 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 OpenSndVoyager/premake5.lua create mode 100644 OpenSndVoyager/src/OpenSndVoyager.cpp create mode 100644 OpenSndVoyager/src/OpenSndVoyager.h create mode 100644 OpenSndVoyager/src/OpenSndVoyager.rc create mode 100644 OpenSndVoyager/src/resource.h create mode 100644 appveyor.yml create mode 100644 build.ps1 create mode 100644 premake5.bat create mode 100644 premake5.exe create mode 100644 premake5.lua diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7559923 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +*.sln +*.vcxproj +*.vcxproj.filters +.vs/ +build/ +Debug/ + +ParrotLoader/Release/ + +Release/ + +TeknoParrot\.sdf + +TeknoParrot\.v12\.suo + +TeknoParrot/TeknoParrot\.vcxproj\.user + +ParrotLoader/ParrotLoader\.vcxproj\.user + +*.user +*.aps \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + 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 +state 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 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 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program 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, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU 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. But first, please read +. diff --git a/OpenSndVoyager/premake5.lua b/OpenSndVoyager/premake5.lua new file mode 100644 index 0000000..5872a70 --- /dev/null +++ b/OpenSndVoyager/premake5.lua @@ -0,0 +1,19 @@ +project "OpenSndVoyager" + targetname "OpenSndVoyager" + language "C++" + kind "SharedLib" + removeplatforms { "x64" } + + files + { + "src/**.cpp", "src/**.h", + "deps/cpp/**.cpp", "deps/inc/**.h", + "src/OpenSndVoyager.aps", "src/OpenSndVoyager.rc" + } + + includedirs { "src" } + +postbuildcommands { + "if not exist $(TargetDir)output mkdir $(TargetDir)output", + "{COPY} $(TargetDir)OpenSndVoyager.dll $(TargetDir)output/" +} \ No newline at end of file diff --git a/OpenSndVoyager/src/OpenSndVoyager.cpp b/OpenSndVoyager/src/OpenSndVoyager.cpp new file mode 100644 index 0000000..ff7299d --- /dev/null +++ b/OpenSndVoyager/src/OpenSndVoyager.cpp @@ -0,0 +1,808 @@ +/* +* Created by Harm for TeknoParrot +* This file is part of the OpenParrot project - https://teknoparrot.com / https://github.com/teknogods +* +* See LICENSE and MENTIONS in the root of the source tree for information +* regarding licensing. +*/ + +extern "C" { + #include "OpenSndVoyager.h" +} +#include +#include +#pragma comment(lib, "xaudio2.lib") +#include +#pragma comment(lib, "shlwapi.lib") + +#ifdef _DEBUG +void info(const char* format, ...) +{ + va_list args; + char buffer[1024]; + + va_start(args, format); + int len = _vsnprintf_s(buffer, sizeof(buffer), format, args); + va_end(args); + + buffer[len] = '\n'; + buffer[len + 1] = '\0'; + + OutputDebugStringA(buffer); +} +#else +#define info(x, ...) {} +#endif + + +struct qSample +{ + WORD sample; + BYTE speed; + BYTE level; + WORD stay; + qSample(WORD sample, BYTE speed, BYTE level, WORD stay) : sample(sample), speed(speed), level(level), stay(stay) {} +}; + +struct BUFFER +{ + WAVEFORMATEX xaFormat; + XAUDIO2_BUFFER xaBuffer; + IXAudio2SourceVoice* xaVoice; + XA2Callback xaCallback; + BOOL playing; + BOOL loop; + std::vector qSamples; + SHORT qIndex; +}; + +// Buffers +BUFFER channelBuffer[CHANNELS]; +//SAMPLE sampleBuffer[SAMPLES]; +DWORD hexSize = 0x12E08; +BYTE* pHexBuffer = new BYTE[hexSize]; + +DWORD sampleHeadersSize = 0x6DD0; +BYTE* pSampleHeaders = new BYTE[sampleHeadersSize]; + +// Xaudio2 +IXAudio2* pXAudio2 = NULL; +IXAudio2MasteringVoice* pMasterVoice = NULL; +BYTE* pDataBuffer = NULL; +DWORD binSize = 0x100000; +DWORD bufferSize = binSize * 4; +BOOL bufferReady = FALSE; +DWORD sampleCount = 0; + +float restMultiplier = 4.4f; + +void XA2Callback::OnBufferEnd(void* cxt) +{ + info("OnBufferEnd channel: %u qIndex: %d qSamples size: %d", channel, channelBuffer[channel].qIndex, channelBuffer[channel].qSamples.size()); + + if (!channelBuffer[channel].playing) + StopChannel(channel); + + if (channelBuffer[channel].qIndex < channelBuffer[channel].qSamples.size() - 1) + { + PlayChannelNext(channel); + } + else + { + channelBuffer[channel].playing = FALSE; + } +} + +const BYTE blob[4256] = { 0x83, 0xF3, 0x00, 0x00, 0xB9, 0xFF, 0x00, 0x00, 0xA7, 0xFF, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xB2, 0x8F, 0x00, 0x00, 0xE1, 0xB7, 0x00, 0x00, 0x79, 0xB7, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xBE, 0xE8, 0x00, 0x00, 0xA9, 0xFB, 0x00, 0x00, 0x80, 0xF9, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x64, 0x00, 0x00, 0x18, 0x62, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x78, 0x00, 0x00, 0xF4, 0x46, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xD2, 0xEC, 0x00, 0x00, 0xF5, 0xFF, 0x00, 0x00, 0xF1, 0xFF, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x40, 0x74, 0x00, 0x00, 0xC9, 0xBF, 0x00, 0x00, 0x40, 0xBF, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xDF, 0xC0, 0x00, 0x00, 0xC4, 0xDD, 0x00, 0x00, 0x0A, 0xDC, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x54, 0x00, 0x00, 0x3D, 0x54, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xB2, 0xF1, 0x00, 0x00, 0x12, 0xFD, 0x00, 0x00, 0xFE, 0xFC, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x73, 0xCC, 0x00, 0x00, 0xB1, 0xF1, 0x00, 0x00, 0xA1, 0xF1, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0xCA, 0x00, 0x00, 0xF7, 0xEE, 0x00, 0x00, 0xF0, 0xEE, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x1E, 0x58, 0x00, 0x00, 0xCE, 0x93, 0x00, 0x00, 0x5F, 0x92, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x40, 0xCE, 0x00, 0x00, 0x54, 0xF4, 0x00, 0x00, 0x4C, 0xF4, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x9B, 0xB7, 0x00, 0x00, 0x94, 0xED, 0x00, 0x00, 0x62, 0xED, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x4A, 0xEE, 0x00, 0x00, 0xEE, 0xFA, 0x00, 0x00, 0xE8, 0xFA, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x36, 0xEC, 0x00, 0x00, 0x2E, 0xFF, 0x00, 0x00, 0x29, 0xFF, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xBC, 0x9B, 0x00, 0x00, 0x63, 0xC8, 0x00, 0x00, 0xF8, 0xC2, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xFA, 0xEE, 0x00, 0x00, 0x26, 0xF8, 0x00, 0x00, 0x21, 0xF8, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x71, 0xCF, 0x00, 0x00, 0x84, 0xF0, 0x00, 0x00, 0x47, 0xF0, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x16, 0xC6, 0x00, 0x00, 0x44, 0xE4, 0x00, 0x00, 0xF2, 0xE3, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x7E, 0xC3, 0x00, 0x00, 0x2E, 0xFE, 0x00, 0x00, 0x7D, 0xEC, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5B, 0x7C, 0x00, 0x00, 0x0D, 0x41, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xC3, 0xDB, 0x00, 0x00, 0x4A, 0xFE, 0x00, 0x00, 0x36, 0xFE, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x34, 0xD9, 0x00, 0x00, 0x8C, 0xF2, 0x00, 0x00, 0x4A, 0xF1, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xD8, 0x5B, 0x00, 0x00, 0x9E, 0x98, 0x00, 0x00, 0x4C, 0x98, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x5E, 0x00, 0x00, 0xEC, 0x5C, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x7E, 0x00, 0x00, 0x64, 0x49, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x7E, 0x00, 0x00, 0x36, 0x52, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x78, 0x00, 0x00, 0xA2, 0xC7, 0x00, 0x00, 0x8B, 0xC7, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x79, 0x00, 0x00, 0xDA, 0x79, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x65, 0xCC, 0x00, 0x00, 0xCF, 0xEC, 0x00, 0x00, 0xA5, 0xEA, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0xC0, 0xD0, 0x00, 0x00, 0x0C, 0xF7, 0x00, 0x00, 0xC8, 0xF4, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xA7, 0x00, 0x00, 0x14, 0xDB, 0x00, 0x00, 0xD0, 0xD8, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x1A, 0x99, 0x00, 0x00, 0x38, 0x97, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0xD4, 0x5B, 0x00, 0x00, 0x93, 0x98, 0x00, 0x00, 0x86, 0x98, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x74, 0x5E, 0x00, 0x00, 0xB2, 0x9C, 0x00, 0x00, 0x44, 0x9B, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xB4, 0x77, 0x00, 0x00, 0x25, 0xC6, 0x00, 0x00, 0x6A, 0xC5, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xA5, 0x98, 0x00, 0x00, 0x1F, 0xC4, 0x00, 0x00, 0x0F, 0xC4, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xA4, 0x5C, 0x00, 0x00, 0x0D, 0x9A, 0x00, 0x00, 0xA5, 0x5C, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x5B, 0x00, 0x00, 0x9E, 0x5B, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x8F, 0xEC, 0x00, 0x00, 0xCE, 0xFE, 0x00, 0x00, 0xAA, 0xFE, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3E, 0xEE, 0x00, 0x00, 0xB5, 0xF6, 0x00, 0x00, 0xB4, 0xF6, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xF4, 0xF3, 0x00, 0x00, 0x0C, 0xF8, 0x00, 0x00, 0xFC, 0xF7, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x62, 0x00, 0x00, 0xCE, 0x61, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x75, 0x00, 0x00, 0x0C, 0x75, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x71, 0x00, 0x00, 0x8D, 0x71, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0xE6, 0xB8, 0x00, 0x00, 0x15, 0xD5, 0x00, 0x00, 0xE6, 0xB8, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xE7, 0x7A, 0x00, 0x00, 0xFE, 0xCA, 0x00, 0x00, 0xE4, 0xCA, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x5B, 0x00, 0x00, 0xEC, 0x5B, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x40, 0xD3, 0x00, 0x00, 0x71, 0xF4, 0x00, 0x00, 0x40, 0xF4, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0xD3, 0xBC, 0x00, 0x00, 0x33, 0xD9, 0x00, 0x00, 0xF3, 0xD8, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xB3, 0x9C, 0x00, 0x00, 0x4F, 0xCB, 0x00, 0x00, 0xF3, 0xCA, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x95, 0xA9, 0x00, 0x00, 0x50, 0xA9, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x15, 0xC7, 0x00, 0x00, 0x17, 0xE6, 0x00, 0x00, 0xF5, 0xE5, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x0B, 0xEB, 0x00, 0x00, 0xBB, 0xFC, 0x00, 0x00, 0xB6, 0xFC, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xD4, 0xB9, 0x00, 0x00, 0x16, 0xF0, 0x00, 0x00, 0x0D, 0xF0, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x40, 0x5F, 0x00, 0x00, 0xC2, 0x9D, 0x00, 0x00, 0x60, 0x9D, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x54, 0x00, 0x00, 0xA7, 0x53, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x5B, 0x00, 0x00, 0x2A, 0x5B, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x4B, 0x62, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0xF0, 0xA0, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x80, 0x59, 0x00, 0x00, 0xFF, 0x95, 0x00, 0x00, 0xAF, 0x95, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x7A, 0x00, 0x00, 0x40, 0x79, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x65, 0x00, 0x00, 0xE8, 0x64, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xE4, 0x5B, 0x00, 0x00, 0xC6, 0x98, 0x00, 0x00, 0xAA, 0x98, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x77, 0x00, 0x00, 0x1C, 0x77, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB3, 0x77, 0x00, 0x00, 0x40, 0x77, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x6E, 0x00, 0x00, 0xF5, 0x6D, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x48, 0x94, 0x00, 0x00, 0x04, 0xBE, 0x00, 0x00, 0xFB, 0xBD, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0xBF, 0xAF, 0x00, 0x00, 0x34, 0xE5, 0x00, 0x00, 0xE2, 0xE4, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x91, 0xA8, 0x00, 0x00, 0xC2, 0xDB, 0x00, 0x00, 0x6E, 0xDB, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x9B, 0x72, 0x00, 0x00, 0x66, 0xBC, 0x00, 0x00, 0x5E, 0xBC, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x91, 0xA9, 0x00, 0x00, 0xFA, 0xA8, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xDA, 0xBA, 0x00, 0x00, 0xF0, 0xF1, 0x00, 0x00, 0xD3, 0xF1, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x72, 0x00, 0x00, 0x44, 0x72, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x95, 0x5D, 0x00, 0x00, 0xBC, 0x9B, 0x00, 0x00, 0xB9, 0x9B, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xDB, 0xE7, 0x00, 0x00, 0x7C, 0xFF, 0x00, 0x00, 0xDC, 0xE7, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xE2, 0x5F, 0x00, 0x00, 0x81, 0x9E, 0x00, 0x00, 0x80, 0x9E, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x9B, 0xD7, 0x00, 0x00, 0x0E, 0xFA, 0x00, 0x00, 0x0A, 0xFA, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xCF, 0xD3, 0x00, 0x00, 0x3F, 0xF6, 0x00, 0x00, 0x3B, 0xF6, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x16, 0xDB, 0x00, 0x00, 0x96, 0xFD, 0x00, 0x00, 0x91, 0xFD, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xEA, 0xD7, 0x00, 0x00, 0x5D, 0xFA, 0x00, 0x00, 0x58, 0xFA, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x80, 0x7B, 0x00, 0x00, 0x73, 0xCC, 0x00, 0x00, 0x18, 0xCB, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x98, 0xD1, 0x00, 0x00, 0x1C, 0xF8, 0x00, 0x00, 0x9D, 0xD1, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA8, 0xD3, 0x00, 0x00, 0xFF, 0xFA, 0x00, 0x00, 0xAC, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xC6, 0x00, 0x00, 0x08, 0xEB, 0x00, 0x00, 0xED, 0xC6, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xB4, 0xE1, 0x00, 0x00, 0xED, 0xFC, 0x00, 0x00, 0xE4, 0xFC, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xDF, 0x6D, 0x00, 0x00, 0xBE, 0xAF, 0x00, 0x00, 0x81, 0xAF, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x65, 0x00, 0x00, 0xE0, 0x64, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x14, 0x5E, 0x00, 0x00, 0x48, 0x9C, 0x00, 0x00, 0x2E, 0x9C, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x31, 0x9A, 0x00, 0x00, 0x14, 0xC7, 0x00, 0x00, 0x09, 0xC7, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x78, 0x00, 0x00, 0x70, 0x78, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xA7, 0xC4, 0x00, 0x00, 0x7A, 0xFF, 0x00, 0x00, 0x63, 0xFF, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB7, 0x74, 0x00, 0x00, 0xA7, 0x74, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x81, 0x9E, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0xE8, 0xCF, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x8C, 0x62, 0x00, 0x00, 0x75, 0xA1, 0x00, 0x00, 0x32, 0xA1, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x9F, 0x65, 0x00, 0x00, 0xFE, 0xA4, 0x00, 0x00, 0xFC, 0xA4, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x25, 0x68, 0x00, 0x00, 0xFC, 0xA7, 0x00, 0x00, 0xF7, 0xA7, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xE4, 0xF5, 0x00, 0x00, 0x98, 0xFC, 0x00, 0x00, 0x95, 0xFC, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x71, 0x00, 0x00, 0xFB, 0x71, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x58, 0x00, 0x00, 0x08, 0x58, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0xBD, 0xC9, 0x00, 0x00, 0x39, 0xC9, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x80, 0x71, 0x00, 0x00, 0x1F, 0xB7, 0x00, 0x00, 0xA0, 0xB6, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xE6, 0xEC, 0x00, 0x00, 0x18, 0xFC, 0x00, 0x00, 0x15, 0xFC, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x70, 0xEE, 0x00, 0x00, 0xE7, 0xFC, 0x00, 0x00, 0xDF, 0xFC, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x16, 0xCC, 0x00, 0x00, 0x36, 0xEC, 0x00, 0x00, 0xF6, 0xEB, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x13, 0x7C, 0x00, 0x00, 0x73, 0xCD, 0x00, 0x00, 0x68, 0xCD, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5F, 0x00, 0x00, 0x13, 0x5F, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x05, 0xBE, 0x00, 0x00, 0x84, 0xDA, 0x00, 0x00, 0x6D, 0xDA, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x26, 0xC6, 0x00, 0x00, 0x86, 0xE9, 0x00, 0x00, 0x46, 0xE9, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x44, 0xF5, 0x00, 0x00, 0xB3, 0xFA, 0x00, 0x00, 0xB0, 0xFA, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xA3, 0xE2, 0x00, 0x00, 0xF0, 0xFD, 0x00, 0x00, 0xDE, 0xFD, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x7C, 0x00, 0x00, 0x39, 0x7C, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x75, 0x00, 0x00, 0x40, 0x75, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x82, 0xBD, 0x00, 0x00, 0x43, 0xF5, 0x00, 0x00, 0x82, 0xBD, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xD1, 0x7F, 0x00, 0x00, 0xA2, 0xD3, 0x00, 0x00, 0xBE, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA9, 0x6F, 0x00, 0x00, 0x48, 0xB4, 0x00, 0x00, 0x05, 0xB4, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x5C, 0x7C, 0x00, 0x00, 0x81, 0xCE, 0x00, 0x00, 0xFD, 0xCD, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x8D, 0xF2, 0x00, 0x00, 0x92, 0xFF, 0x00, 0x00, 0x7C, 0xFF, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x5E, 0x00, 0x00, 0xF8, 0x5C, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0xF7, 0xB2, 0x00, 0x00, 0x90, 0xE8, 0x00, 0x00, 0x24, 0xE8, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xA7, 0x9D, 0x00, 0x00, 0x89, 0xCD, 0x00, 0x00, 0x55, 0xCD, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA9, 0x6F, 0x00, 0x00, 0xE4, 0x6E, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x58, 0x00, 0x00, 0x2C, 0x58, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x72, 0x00, 0x00, 0xCA, 0x72, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x5B, 0x00, 0x00, 0xB4, 0x5B, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xCF, 0xF7, 0x00, 0x00, 0x21, 0xFF, 0x00, 0x00, 0x17, 0xFF, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xB0, 0x68, 0x00, 0x00, 0x91, 0xA8, 0x00, 0x00, 0x2C, 0xA8, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x40, 0x7A, 0x00, 0x00, 0x40, 0xCA, 0x00, 0x00, 0x3C, 0xCA, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xFE, 0xA4, 0x00, 0x00, 0x9B, 0xD7, 0x00, 0x00, 0x98, 0xD7, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x68, 0x00, 0x00, 0x22, 0x68, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xCA, 0xBF, 0x00, 0x00, 0xCF, 0xF7, 0x00, 0x00, 0xCC, 0xF7, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x96, 0xA9, 0x00, 0x00, 0x8B, 0xDD, 0x00, 0x00, 0x88, 0xDD, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7A, 0x6E, 0x00, 0x00, 0x77, 0x6E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x68, 0x00, 0x00, 0xAD, 0x68, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xC2, 0x5F, 0x00, 0x00, 0x4E, 0x9E, 0x00, 0x00, 0x4B, 0x9E, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6D, 0x00, 0x00, 0x74, 0x6D, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xC9, 0x65, 0x00, 0x00, 0x4D, 0xA5, 0x00, 0x00, 0x4A, 0xA5, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xF6, 0xE9, 0x00, 0x00, 0x91, 0xFE, 0x00, 0x00, 0x8E, 0xFE, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x77, 0x00, 0x00, 0x7B, 0x77, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x72, 0x00, 0x00, 0x98, 0x72, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xC3, 0x9D, 0x00, 0x00, 0xCC, 0xCD, 0x00, 0x00, 0xC9, 0xCD, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0xAC, 0x71, 0x00, 0x00, 0x9B, 0xB7, 0x00, 0x00, 0x98, 0xB7, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x87, 0xCF, 0x00, 0x00, 0xCE, 0xF5, 0x00, 0x00, 0xCB, 0xF5, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xAB, 0xC7, 0x00, 0x00, 0x1E, 0xEC, 0x00, 0x00, 0x0D, 0xEC, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x40, 0x54, 0x00, 0x00, 0xB1, 0x8F, 0x00, 0x00, 0xA3, 0x8F, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xDD, 0xC5, 0x00, 0x00, 0xA6, 0xE8, 0x00, 0x00, 0xA0, 0xE8, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xFF, 0xCA, 0x00, 0x00, 0xFE, 0xEF, 0x00, 0x00, 0xE0, 0xEF, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0xE3, 0x00, 0x00, 0x76, 0xFE, 0x00, 0x00, 0x5B, 0xFE, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x17, 0x90, 0x00, 0x00, 0xE5, 0xB8, 0x00, 0x00, 0xB6, 0xB8, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x8A, 0xF0, 0x00, 0x00, 0x72, 0xFF, 0x00, 0x00, 0x71, 0xFF, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x89, 0xCD, 0x00, 0x00, 0x70, 0xEE, 0x00, 0x00, 0x45, 0xEE, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x15, 0xD5, 0x00, 0x00, 0x4A, 0xEE, 0x00, 0x00, 0x1C, 0xEE, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x5F, 0xD1, 0x00, 0x00, 0xE3, 0xF7, 0x00, 0x00, 0xBE, 0xF7, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xCC, 0xCD, 0x00, 0x00, 0xBB, 0xEE, 0x00, 0x00, 0x95, 0xEE, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x4D, 0xA5, 0x00, 0x00, 0xE9, 0xD7, 0x00, 0x00, 0xE6, 0xD7, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xE0, 0xEA, 0x00, 0x00, 0xD5, 0xFD, 0x00, 0x00, 0xD4, 0xFD, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xBB, 0xEE, 0x00, 0x00, 0x3F, 0xFD, 0x00, 0x00, 0x33, 0xFD, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x73, 0xCD, 0x00, 0x00, 0x83, 0xF3, 0x00, 0x00, 0x61, 0xF3, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xEC, 0xD3, 0x00, 0x00, 0x8F, 0xEC, 0x00, 0x00, 0x8E, 0xEC, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xFF, 0x95, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x1E, 0xC0, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x49, 0x9C, 0x00, 0x00, 0x4E, 0xC9, 0x00, 0x00, 0x09, 0xC9, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x54, 0x9D, 0x00, 0x00, 0x64, 0xCC, 0x00, 0x00, 0x14, 0xCC, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x77, 0x6D, 0x00, 0x00, 0xA8, 0xAE, 0x00, 0x00, 0x98, 0xAE, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xD6, 0x72, 0x00, 0x00, 0xE2, 0xBD, 0x00, 0x00, 0xCA, 0xBD, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x4F, 0xC9, 0x00, 0x00, 0xBD, 0xE8, 0x00, 0x00, 0xA8, 0xE8, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x84, 0xDA, 0x00, 0x00, 0x53, 0xF4, 0x00, 0x00, 0x33, 0xF4, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x90, 0xE8, 0x00, 0x00, 0xBE, 0xFB, 0x00, 0x00, 0xA7, 0xFB, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xF1, 0xC2, 0x00, 0x00, 0xDC, 0xDF, 0x00, 0x00, 0xC0, 0xDF, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x05, 0xE4, 0x00, 0x00, 0xF4, 0xFF, 0x00, 0x00, 0xDC, 0xFF, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x8B, 0xDD, 0x00, 0x00, 0x2D, 0xF9, 0x00, 0x00, 0x1A, 0xF9, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xFF, 0xEF, 0x00, 0x00, 0xD2, 0xF9, 0x00, 0x00, 0xCA, 0xF9, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1F, 0xEC, 0x00, 0x00, 0x1E, 0xFE, 0x00, 0x00, 0x0E, 0xFE, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x7A, 0x6E, 0x00, 0x00, 0xD0, 0xB1, 0x00, 0x00, 0xFA, 0xB0, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x4F, 0xE7, 0x00, 0x00, 0xE2, 0xFF, 0x00, 0x00, 0x9F, 0xFF, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x90, 0x58, 0x00, 0x00, 0x48, 0x94, 0x00, 0x00, 0xD0, 0x93, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0xB2, 0xAE, 0x00, 0x00, 0x05, 0xE4, 0x00, 0x00, 0xD4, 0xE3, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x87, 0x6E, 0x00, 0x00, 0xF7, 0xB2, 0x00, 0x00, 0xF4, 0xB2, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xC7, 0xDD, 0x00, 0x00, 0x94, 0xF8, 0x00, 0x00, 0x91, 0xF8, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0xE4, 0x5B, 0x00, 0x00, 0xF6, 0x98, 0x00, 0x00, 0xF3, 0x98, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x67, 0xBC, 0x00, 0x00, 0xF4, 0xF3, 0x00, 0x00, 0xF1, 0xF3, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x16, 0x72, 0x00, 0x00, 0xD4, 0xB9, 0x00, 0x00, 0xBD, 0xB9, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x7C, 0x00, 0x00, 0xC7, 0x7B, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x29, 0xC4, 0x00, 0x00, 0xB4, 0xE1, 0x00, 0x00, 0x80, 0xE1, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0xB3, 0xDC, 0x00, 0x00, 0x5B, 0xDC, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0xDC, 0xDF, 0x00, 0x00, 0xEA, 0xFA, 0x00, 0x00, 0xA4, 0xFA, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x9C, 0xC1, 0x00, 0x00, 0x2D, 0xFC, 0x00, 0x00, 0x1D, 0xFC, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0x5F, 0x00, 0x00, 0xC8, 0x5F, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0xE3, 0xBD, 0x00, 0x00, 0xE4, 0xF5, 0x00, 0x00, 0xB3, 0xF5, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0D, 0x5A, 0x00, 0x00, 0x9F, 0x96, 0x00, 0x00, 0x8A, 0x96, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x5E, 0x00, 0x00, 0x93, 0x5E, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2D, 0x9D, 0x00, 0x00, 0x16, 0xCC, 0x00, 0x00, 0xF3, 0xCB, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x35, 0xE5, 0x00, 0x00, 0x9C, 0xFD, 0x00, 0x00, 0x8F, 0xFD, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x95, 0xED, 0x00, 0x00, 0xBD, 0xFD, 0x00, 0x00, 0x9E, 0xFD, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4B, 0x62, 0x00, 0x00, 0xBF, 0x61, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0xE2, 0xB7, 0x00, 0x00, 0xEC, 0xD3, 0x00, 0x00, 0xB5, 0xD3, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xB3, 0xDC, 0x00, 0x00, 0x2F, 0xF7, 0x00, 0x00, 0xDC, 0xF6, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x4E, 0x9E, 0x00, 0x00, 0x71, 0xCF, 0x00, 0x00, 0x3D, 0xCF, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x20, 0xB7, 0x00, 0x00, 0xE6, 0xEC, 0x00, 0x00, 0xD4, 0xEC, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x5B, 0x00, 0x00, 0xB3, 0x5B, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x81, 0xCE, 0x00, 0x00, 0xB1, 0xF4, 0x00, 0x00, 0xAE, 0xF4, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x18, 0xE6, 0x00, 0x00, 0xAC, 0xFD, 0x00, 0x00, 0xA9, 0xFD, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x6D, 0x7E, 0x00, 0x00, 0x98, 0xD1, 0x00, 0x00, 0x95, 0xD1, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x99, 0x00, 0x00, 0x16, 0xC6, 0x00, 0x00, 0x13, 0xC6, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x50, 0xCB, 0x00, 0x00, 0xE0, 0xEA, 0x00, 0x00, 0xDD, 0xEA, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x86, 0xE9, 0x00, 0x00, 0x33, 0xFF, 0x00, 0x00, 0x30, 0xFF, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xB8, 0xDF, 0x00, 0x00, 0x61, 0xFB, 0x00, 0x00, 0x5C, 0xFB, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xFA, 0xEE, 0x00, 0x00, 0x4D, 0xFF, 0x00, 0x00, 0x4A, 0xFF, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x01, 0xA1, 0x00, 0x00, 0x40, 0xD3, 0x00, 0x00, 0x3C, 0xD3, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x35, 0x7E, 0x00, 0x00, 0x5F, 0xD1, 0x00, 0x00, 0x5A, 0xD1, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xA7, 0xE8, 0x00, 0x00, 0xAE, 0xFD, 0x00, 0x00, 0xAB, 0xFD, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xD0, 0xB1, 0x00, 0x00, 0x4F, 0xE7, 0x00, 0x00, 0x4C, 0xE7, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x7D, 0x00, 0x00, 0xBD, 0x7D, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xC7, 0x98, 0x00, 0x00, 0xD6, 0xC4, 0x00, 0x00, 0xD3, 0xC4, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0xD4, 0x93, 0x00, 0x00, 0xD3, 0xBC, 0x00, 0x00, 0xD0, 0xBC, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x21, 0xC5, 0x00, 0x00, 0x20, 0xE3, 0x00, 0x00, 0x0C, 0xE3, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x7F, 0x00, 0x00, 0xCE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xB4, 0x00, 0x00, 0xF6, 0xE9, 0x00, 0x00, 0x4C, 0xE9, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0xA6, 0x69, 0x00, 0x00, 0x7C, 0xAA, 0x00, 0x00, 0xCB, 0xA9, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xF6, 0x98, 0x00, 0x00, 0x21, 0xC5, 0x00, 0x00, 0x7E, 0xC4, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x7C, 0xAA, 0x00, 0x00, 0xB8, 0xDF, 0x00, 0x00, 0xA7, 0xDF, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xCD, 0xB8, 0x00, 0x00, 0xFA, 0xEE, 0x00, 0x00, 0xB3, 0xEE, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x27, 0x5F, 0x00, 0x00, 0xA7, 0x9D, 0x00, 0x00, 0x1B, 0x9D, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x01, 0xD0, 0x00, 0x00, 0x30, 0xF1, 0x00, 0x00, 0x79, 0xF0, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0xB1, 0x5E, 0x00, 0x00, 0x2D, 0x9D, 0x00, 0x00, 0x00, 0x9D, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xD6, 0xC4, 0x00, 0x00, 0xA3, 0xE2, 0x00, 0x00, 0x17, 0xE2, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0xD7, 0x5E, 0x00, 0x00, 0x54, 0x9D, 0x00, 0x00, 0xC0, 0x9C, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x75, 0xA1, 0x00, 0x00, 0xCF, 0xD3, 0x00, 0x00, 0x4C, 0xD3, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0xE1, 0x7C, 0x00, 0x00, 0x87, 0xCF, 0x00, 0x00, 0x82, 0xCF, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6F, 0x72, 0x00, 0x00, 0xDA, 0xBA, 0x00, 0x00, 0xD7, 0xBA, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x40, 0x7C, 0x00, 0x00, 0x40, 0xCE, 0x00, 0x00, 0x3D, 0xCE, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xBE, 0xC9, 0x00, 0x00, 0x3E, 0xEE, 0x00, 0x00, 0x3B, 0xEE, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x10, 0x78, 0x00, 0x00, 0xE6, 0xC6, 0x00, 0x00, 0xE3, 0xC6, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x27, 0x77, 0x00, 0x00, 0xA7, 0xC4, 0x00, 0x00, 0xA4, 0xC4, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xAC, 0x72, 0x00, 0x00, 0x82, 0xBD, 0x00, 0x00, 0x7F, 0xBD, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xB8, 0x74, 0x00, 0x00, 0x78, 0xC0, 0x00, 0x00, 0x75, 0xC0, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x9F, 0x96, 0x00, 0x00, 0xDF, 0xC0, 0x00, 0x00, 0xDC, 0xC0, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x78, 0xC0, 0x00, 0x00, 0xF1, 0xF8, 0x00, 0x00, 0xEE, 0xF8, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0xFD, 0x68, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x71, 0x00, 0x00, 0x7D, 0x71, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x1C, 0x75, 0x00, 0x00, 0x9C, 0xC1, 0x00, 0x00, 0x99, 0xC1, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x74, 0x00, 0x00, 0x3D, 0x74, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7B, 0x00, 0x00, 0x7D, 0x7B, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x59, 0x00, 0x00, 0x7D, 0x59, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0x72, 0x00, 0x00, 0xA9, 0x72, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x72, 0x00, 0x00, 0x13, 0x72, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xD2, 0xDC, 0x00, 0x00, 0x63, 0xFF, 0x00, 0x00, 0x60, 0xFF, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0x6D, 0x00, 0x00, 0xDC, 0x6D, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xFF, 0x75, 0x00, 0x00, 0x7E, 0xC3, 0x00, 0x00, 0x7B, 0xC3, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x5F, 0x00, 0x00, 0xBF, 0x5F, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x5C, 0x00, 0x00, 0xA1, 0x5C, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x5D, 0x00, 0x00, 0x92, 0x5D, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x5E, 0x00, 0x00, 0x71, 0x5E, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x7C, 0x00, 0x00, 0xDE, 0x7C, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x5A, 0x00, 0x00, 0x0A, 0x5A, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x96, 0x54, 0x00, 0x00, 0x17, 0x90, 0x00, 0x00, 0x14, 0x90, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x7A, 0x00, 0x00, 0xE4, 0x7A, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x7E, 0x77, 0x00, 0x00, 0xDD, 0xC5, 0x00, 0x00, 0xDA, 0xC5, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x49, 0xE4, 0x00, 0x00, 0xD1, 0xFF, 0x00, 0x00, 0xCE, 0xFF, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0xCD, 0xB8, 0x00, 0x00, 0xCA, 0xB8, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0xBE, 0xC8, 0x00, 0x00, 0xDB, 0xE7, 0x00, 0x00, 0xD8, 0xE7, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x94, 0x98, 0x00, 0x00, 0xF1, 0xC2, 0x00, 0x00, 0xEE, 0xC2, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0xC0, 0x7D, 0x00, 0x00, 0xC0, 0xD0, 0x00, 0x00, 0xBD, 0xD0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x92, 0xA9, 0x00, 0x00, 0xD2, 0xDC, 0x00, 0x00, 0xCF, 0xDC, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00 }; +const FLOAT volumeLookup[11] = { 0.0, 0.013362, 0.032258, 0.058982, 0.096774, 0.150221, 0.225806, 0.3327, 0.483871, 0.697659, 1.0 }; + +// Make a byte from 2 ASCII bytes +int getByte(char msb, char lsb) +{ + int result = 0; + char combo[2] = { msb, lsb }; + + result = strtol(combo, NULL, 16); + + return result; +} + +void SetMasterVolume(DWORD level) +{ + float volume = volumeLookup[level]; + info("OpenSndVoyager::SetMasterVolume level: %u volume: %f", level, volume); + + CHECK_HR(pMasterVoice->SetVolume(volume)); +} + +__declspec(dllexport) void snd_init_new(DWORD level) +{ + info("OpenSndVoyager::snd_init_new level: %u", level); + + bufferReady = FALSE; + DWORD bytesRead = 0; // this is needed for windows 7 + + char buf[MAX_PATH]; + memset(buf, 0, sizeof(buf)); + GetCurrentDirectoryA(256, buf); + auto len = strlen(buf); + buf[len] = '\\'; + strcat_s(buf, "stv\\arom\\"); + + pDataBuffer = new BYTE[bufferSize]; + + for (BYTE i = 0; i < 4; i++) + { + char filePath[MAX_PATH]; + sprintf_s(filePath, "%svoyager%u.bin", buf, i); + info("OpenSndVoyager::snd_init_new loading %s", filePath); + + HANDLE hFile = CreateFileA((LPCSTR)filePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + info("OpenSndVoyager::snd_init_new ERROR! Opening file failed(%u)", GetLastError()); + return; + } + + DWORD asdf = GetFileSize(hFile, NULL); + + + if (asdf != binSize) + { + info("OpenSndVoyager::snd_init_new ERROR! Wrong file size! (%u)", asdf); + return; + } + + ReadFile(hFile, pDataBuffer + binSize * i, binSize, &bytesRead, NULL); + } + + // Convert to unsigned + for (size_t i = 0; i < bufferSize; i++) + { + pDataBuffer[i] = (BYTE)((char)pDataBuffer[i] + 128); + } + + // Load hex file + char filePath[MAX_PATH]; + sprintf_s(filePath, "%scpuarom.hex", buf); + info("OpenSndVoyager::snd_init_new loading %s", filePath); + HANDLE hFile = CreateFileA(filePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + //HANDLE hFile = CreateFileA("D:\\Arcade\\Star Trek\\stv\\arom\\cpuarom.hex", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + info("ERROR! Opening file failed(%u)", GetLastError()); + return; + } + + DWORD fileSize = GetFileSize(hFile, NULL); + + + if (fileSize != hexSize) + { + info("ERROR! Wrong file size! (%u)", fileSize); + return; + } + + ReadFile(hFile, pHexBuffer, hexSize, &bytesRead, NULL); + + DWORD line = 0; + BOOL done = FALSE; + DWORD lineSize = 44; + + // Read per line + while (done == FALSE) + { + DWORD lOffset = lineSize * line; + BYTE start = pHexBuffer[lOffset + 0]; + BYTE count = getByte(pHexBuffer[lOffset + 1], pHexBuffer[lOffset + 2]); + WORD address = getByte(pHexBuffer[lOffset + 3], pHexBuffer[lOffset + 4]) << 8 | getByte(pHexBuffer[lOffset + 5], pHexBuffer[lOffset + 6]); + BYTE type = getByte(pHexBuffer[lOffset + 7], pHexBuffer[lOffset + 8]); + + //info("line: %d start: %X count: %X address: %04X type: %X data:", line, start, count, address, type); + + if (type == 0x01) + { + done = TRUE; + continue; + } + + if (start == 0x3A && count == 0x10 && address >= 0x00 && address <= sampleHeadersSize) + { + DWORD cursor = address; + for (BYTE i = 9; i < 41; i += 2) + { + BYTE data = getByte(pHexBuffer[lOffset + i], pHexBuffer[lOffset + i + 1]); + //printf(" %02X", data); + pSampleHeaders[cursor] = data; + cursor++; + } + //printf("\n"); + } + else + { + // Error + info("hex error"); + return; + } + + line++; + } + + // Init xAudio2 + CoInitialize(nullptr); + CHECK_HR(XAudio2Create(&pXAudio2)); + CHECK_HR(pXAudio2->CreateMasteringVoice(&pMasterVoice)); + + //CHECK_HR(pMasterVoice->SetVolume(0.5f)); + SetMasterVolume(level); + + // Init channel buffer + for (BYTE channel = 0; channel < CHANNELS; channel++) + { + ResetChannel(channel); + } + + bufferReady = TRUE; +} + +__declspec(dllexport) void snd_code_always(INT code) +{ + info("OpenSndVoyager::snd_code_always code: %u", code); + +} + +void SetChannelVolume(BYTE channel, BYTE level) +{ + info("OpenSndVoyager::SetChannelVolume channel: %u level: %u", channel, level); + + if (channel >= CHANNELS) { return; } + + if (channelBuffer[channel].xaVoice == NULL) { return; } + + // TODO: do the proper level to volume conversion + + float fVolume = (float)level / 255.0f; + CHECK_HR(channelBuffer[channel].xaVoice->SetVolume(fVolume)); +} + +void SetupChannel(BYTE channel) +{ + info("OpenSndVoyager::SetupChannel channel: %u", channel); + + if (channel >= CHANNELS) { return; } + + WORD sample = channelBuffer[channel].qSamples[0].sample; + BYTE speed = channelBuffer[channel].qSamples[0].speed; + BYTE level = channelBuffer[channel].qSamples[0].level; + WORD stay = channelBuffer[channel].qSamples[0].stay; + BOOL loop = channelBuffer[channel].loop; + + info("OpenSndVoyager::SetupChannel stay: %u", stay); + + DWORD base = 0; + DWORD offsetBegin = 0; + DWORD offsetEnd = 0; + DWORD offsetOther = 0; + DWORD size = 0; + + // Rest + if (sample == 0xFFFF) + { + // Calculate how many bytes we need for ms rest + WORD ms = (WORD)((float)level * restMultiplier); + size = (DWORD)(SpeedToSampleRate(speed) * ms / 1000); + level = 0; + info("OpenSndVoyager::SetupChannel rest ms: %u size: %u", ms, size); + } + else + { + DWORD* pHeader = (DWORD*)blob + (sample * 4); + + base = pHeader[3] * 0x10000; + offsetBegin = base + pHeader[0]; + offsetEnd = base + pHeader[1]; + offsetOther = base + pHeader[2]; + size = offsetEnd - offsetBegin; + } + + info("OpenSndVoyager::SetupChannel channel: %X sample: %u speed: %X", channel, sample, speed); + info("OpenSndVoyager::SetupChannel base: %X offsetBegin: %X offsetEnd: %X offsetOther: %X size: %X", base, offsetBegin, offsetEnd, offsetOther, size); + + // Setup new channel data + auto sampleRate = SpeedToSampleRate(speed); + auto sampleBits = 8; + auto channels = 1; + + channelBuffer[channel].playing = TRUE; + channelBuffer[channel].loop = loop; + channelBuffer[channel].qIndex = 0; + + channelBuffer[channel].xaFormat.nAvgBytesPerSec = (sampleRate * sampleBits * channels) / 8; + channelBuffer[channel].xaFormat.nSamplesPerSec = sampleRate; + channelBuffer[channel].xaFormat.wBitsPerSample = sampleBits; + channelBuffer[channel].xaFormat.nChannels = channels; + channelBuffer[channel].xaFormat.wFormatTag = WAVE_FORMAT_PCM; + channelBuffer[channel].xaFormat.nBlockAlign = (sampleBits * channels) / 8; + + channelBuffer[channel].xaBuffer.AudioBytes = bufferSize; + channelBuffer[channel].xaBuffer.pAudioData = pDataBuffer; + channelBuffer[channel].xaBuffer.Flags = XAUDIO2_END_OF_STREAM; + channelBuffer[channel].xaBuffer.LoopBegin = 0; + channelBuffer[channel].xaBuffer.LoopLength = 0; + channelBuffer[channel].xaBuffer.LoopCount = 0; + channelBuffer[channel].xaBuffer.PlayBegin = offsetBegin; + channelBuffer[channel].xaBuffer.PlayLength = size; + channelBuffer[channel].xaBuffer.pContext = NULL; + + if (loop) + { + channelBuffer[channel].xaBuffer.LoopBegin = channelBuffer[channel].xaBuffer.PlayBegin; + channelBuffer[channel].xaBuffer.LoopLength = channelBuffer[channel].xaBuffer.PlayLength; + channelBuffer[channel].xaBuffer.LoopCount = XAUDIO2_LOOP_INFINITE; + } + + if (stay > 0) + { + float ms = (float)stay * restMultiplier; + float length = (float)size / sampleRate * 1000; + WORD lCount = (WORD)(ms / length); + + info("OpenSndVoyager::SetupChannel ms: %f length: %f lCount: %u", ms, length, lCount); + + if (lCount > 1) + { + channelBuffer[channel].xaBuffer.LoopBegin = channelBuffer[channel].xaBuffer.PlayBegin; + channelBuffer[channel].xaBuffer.LoopLength = channelBuffer[channel].xaBuffer.PlayLength; + channelBuffer[channel].xaBuffer.LoopCount = lCount; + } + } + + channelBuffer[channel].xaCallback.channel = channel; + CHECK_HR(pXAudio2->CreateSourceVoice(&channelBuffer[channel].xaVoice, &channelBuffer[channel].xaFormat, 0, XAUDIO2_DEFAULT_FREQ_RATIO, &channelBuffer[channel].xaCallback)); + SetChannelVolume(channel, level); + CHECK_HR(channelBuffer[channel].xaVoice->SubmitSourceBuffer(&channelBuffer[channel].xaBuffer)); + //CHECK_HR(channelBuffer[channel].xaVoice->Start(0)); +} + +DWORD SpeedToSampleRate(BYTE speed) +{ + info("OpenSndVoyager::SpeedToSampleRate speed: (0x%02X)", speed); + + DWORD sampleRate = 0; + + // This is pretty close but not 100% accurate! + if (speed == 0x20 || speed == 0x25 || speed == 0x26) + { + sampleRate = 8000; + } + else if (speed == 0x30 || speed == 0x31 || speed == 0x32 || speed == 0x2A) + { + sampleRate = 11025; + } + else if (speed == 0x36) + { + sampleRate = 16000; + } + else if (speed == 0x40 || speed == 0x41 || speed == 0x3B) + { + sampleRate = 22050; + } + else if (speed == 0x60) + { + sampleRate = 96000; + } + else + { + info("OpenSndVoyager::SpeedToSampleRate unknown samplerate!! (0x%02X)", speed); + sampleRate = 22050; + } + + return sampleRate; +} + +void PlayChannelNext(BYTE channel) +{ + info("OpenSndVoyager::PlayChannelNext channel: %u", channel); + + if (channel >= CHANNELS) { return; } + + channelBuffer[channel].qIndex++; + + WORD sample = channelBuffer[channel].qSamples[channelBuffer[channel].qIndex].sample; + BYTE speed = channelBuffer[channel].qSamples[channelBuffer[channel].qIndex].speed; + BYTE level = channelBuffer[channel].qSamples[channelBuffer[channel].qIndex].level; + WORD stay = channelBuffer[channel].qSamples[channelBuffer[channel].qIndex].stay; + + info("OpenSndVoyager::SetupChannel stay: %u", stay); + + DWORD base = 0; + DWORD offsetBegin = 0; + DWORD offsetEnd = 0; + DWORD offsetOther = 0; + DWORD size = 0; + + // Rest + if (sample == 0xFFFF) + { + // Calculate how many bytes we need for ms rest + WORD ms = (WORD)((float)level * restMultiplier); + size = (DWORD)(SpeedToSampleRate(speed) * ms / 1000); + level = 0; + info("OpenSndVoyager::PlayChannelNext rest ms: %u size: %u", ms, size); + } + else + { + DWORD* pHeader = (DWORD*)blob + (sample * 4); + + base = pHeader[3] * 0x10000; + offsetBegin = base + pHeader[0]; + offsetEnd = base + pHeader[1]; + offsetOther = base + pHeader[2]; + size = offsetEnd - offsetBegin; + } + + info("OpenSndVoyager::PlayChannelNext channel: %X sample: %u speed: %X", channel, sample, speed); + info("OpenSndVoyager::PlayChannelNext base: %X offsetBegin: %X offsetEnd: %X offsetOther: %X size: %X", base, offsetBegin, offsetEnd, offsetOther, size); + + CHECK_HR(channelBuffer[channel].xaVoice->FlushSourceBuffers()); + + // Setup new channel data + auto sampleRate = SpeedToSampleRate(speed); + auto sampleBits = 8; + auto channels = 1; + + channelBuffer[channel].xaBuffer.AudioBytes = bufferSize; + channelBuffer[channel].xaBuffer.pAudioData = pDataBuffer; + channelBuffer[channel].xaBuffer.Flags = XAUDIO2_END_OF_STREAM; + channelBuffer[channel].xaBuffer.LoopBegin = 0; + channelBuffer[channel].xaBuffer.LoopLength = 0; + channelBuffer[channel].xaBuffer.LoopCount = 0; + channelBuffer[channel].xaBuffer.PlayBegin = offsetBegin; + channelBuffer[channel].xaBuffer.PlayLength = size; + channelBuffer[channel].xaBuffer.pContext = NULL; + + if (stay > 0) + { + float ms = (float)stay * restMultiplier; + float length = (float)size / sampleRate * 1000; + WORD lCount = (WORD)(ms / length); + + info("OpenSndVoyager::SetupChannel ms: %f length: %f lCount: %u", ms, length, lCount); + + if (lCount > 1) + { + channelBuffer[channel].xaBuffer.LoopBegin = channelBuffer[channel].xaBuffer.PlayBegin; + channelBuffer[channel].xaBuffer.LoopLength = channelBuffer[channel].xaBuffer.PlayLength; + channelBuffer[channel].xaBuffer.LoopCount = lCount; + } + } + + + SetChannelVolume(channel, level); + CHECK_HR(channelBuffer[channel].xaVoice->SubmitSourceBuffer(&channelBuffer[channel].xaBuffer)); + CHECK_HR(channelBuffer[channel].xaVoice->Start(0)); +} + +void PlayChannel(BYTE channel) +{ + if (channel >= CHANNELS) { return; } + if (channelBuffer[channel].xaVoice == NULL) { return; } + + info("OpenSndVoyager::PlayChannel Playing channel %u", channel); + + CHECK_HR(channelBuffer[channel].xaVoice->Start(0)); + channelBuffer[channel].playing = TRUE; +} + +void StopChannel(BYTE channel) +{ + if (channel >= CHANNELS) { return; } + //if (!channelBuffer[channel].playing) { return; } + //if (channelBuffer[channel].xaVoice == NULL) { return; } + + info("OpenSndVoyager::StopChannel Stopping channel %u", channel); + if (channelBuffer[channel].playing && channelBuffer[channel].xaVoice != NULL) + { + CHECK_HR(channelBuffer[channel].xaVoice->Stop()); + channelBuffer[channel].playing = FALSE; + } + + ResetChannel(channel); +} + +void StopAllChannels() +{ + info("OpenSndVoyager::StopAllChannels"); + + for (BYTE i = 0; i < CHANNELS; i++) + { + StopChannel(i); + } +} + +void ResetChannel(BYTE channel) +{ + info("ResetChannel %u", channel); + + if (channel >= CHANNELS) { return; } + + // Reset pointers + if (channelBuffer[channel].xaVoice != NULL) + { + //CHECK_HR(channelBuffer[channel].xaVoice->FlushSourceBuffers()); // This causes race condition crash (aug 2020) + channelBuffer[channel].xaVoice->DestroyVoice(); + channelBuffer[channel].xaVoice = NULL; + } + + // Reset rest + channelBuffer[channel].xaFormat = { 0 }; + channelBuffer[channel].xaBuffer = { 0 }; + //channelBuffer[channel].xaCallback = ? ; + channelBuffer[channel].xaVoice = NULL; + channelBuffer[channel].playing = FALSE; + channelBuffer[channel].loop = FALSE; + channelBuffer[channel].qSamples.clear(); + channelBuffer[channel].qIndex = -1; +} + +void AddSampleToChannel(BYTE channel, WORD sample, BYTE speed, BYTE level) +{ + info("AddSampleToChannel channel: %u sample: %u speed: %u level: %u", channel, sample, speed, level); + + if (channel >= CHANNELS) { return; } + + channelBuffer[channel].qSamples.emplace_back(sample, speed, level, 0); +} + +__declspec(dllexport) void sndPlay(INT code) +{ + if (!bufferReady) { info("OpenSndVoyager::sndPlay ERROR! Buffer not ready!"); return; } + + // Skip test menu sounds + //if (code == 0x1b || code == 0x8b) + //{ + //info("opensndvoyager::sndplay ignore test menu sounds!"); + //return; + //} + + info("OpenSndVoyager::sndPlay code: %u", code); + + // Skip these for some reason + if (code == -0x2a474b3 || code == 0xC2) + { + info("OpenSndVoyager::sndPlay Skip!"); + return; + } + + // Master volume control + if (code >= 1000 && code <= 1010) + { + SetMasterVolume(code - 1000); + return; + } + + // Kill all + if (code == 0) + { + StopAllChannels(); + return; + } + + // Final check + //if (code > 499) + //{ + // info("OpenSndVoyager::sndPlay Invalid code!"); + // return; + //} + + // Mute music? + if (MUTE_MUSIC && (code == 4 || code == 5 || code == 6 || code == 7 || code == 20 || code == 22 || code == 26 || code == 36 || code == 188 || code == 189 || code == 196 || code == 268 || code == 301)) + { + return; + } + + WORD hOffset = pSampleHeaders[code * 2] << 8 | pSampleHeaders[code * 2 + 1]; + BYTE* pSampleHeader = pSampleHeaders + hOffset; + + BYTE channel = pSampleHeader[0]; + BYTE unknown1 = pSampleHeader[1]; + BYTE unknown2 = pSampleHeader[2]; + BYTE level = 0xFF; + WORD sample = 0; + BYTE speed = 0x40; + BOOL loop = FALSE; + WORD qSize = 0; + BOOL levelUsed = FALSE; + + // Nothing + if (pSampleHeader[3] == OC_EOS || channel == 0x00) + { + info("OpenSndVoyager::sndPlay Nothing"); + return; + } + + // Parse opcodes + info("OpenSndVoyager::sndPlay parsing"); + ResetChannel(channel); + + BOOL parsing = TRUE; + WORD cursor = 3; + while (parsing) + { + switch (pSampleHeader[cursor]) + { + case OC_REST: + // Add delay (play silence for x ms) + AddSampleToChannel(channel, 0xFFFF, speed, pSampleHeader[cursor + 1]); + cursor += 2; + break; + case OC_START_VOICE: + // Start parallel voice + sndPlay(pSampleHeader[cursor + 1] + 0x200); + cursor += 2; + break; + case OC_SETATTEN: + // Volume + level = pSampleHeader[cursor + 1]; + levelUsed = FALSE; + cursor += 2; + break; + case OC_SETPATCH: + // Found sample + sample = pSampleHeader[cursor + 1] << 8 | pSampleHeader[cursor + 2]; + + // Prevent false detections + if (sample > 676) + { + cursor += 1; + break; + } + + // Some are shorter for some fucking reason + if (pSampleHeader[cursor + 3] >= OC_SET_LUP_CNTL && pSampleHeader[cursor + 3] <= OC_DIAGNOSTIC) + { + cursor += 3; + } + else + { + speed = pSampleHeader[cursor + 3]; + cursor += 5; + } + + AddSampleToChannel(channel, sample, speed, level); + levelUsed = TRUE; + break; + case OC_SETPITCHOFFSET: + // Skip this + cursor += 3; + break; + case OC_STAY: + // Add to last sample + qSize = channelBuffer[channel].qSamples.size(); + + if (qSize > 0) + channelBuffer[channel].qSamples[qSize - 1].stay += pSampleHeader[cursor + 1]; + + cursor += 2; + break; + case OC_SETENVELOPE: + // Fuck this + cursor += 2; + break; + case OC_STRING_BRANCH: + //loop = TRUE; + cursor += 3; + break; + case OC_SETPRIORITY: + // Ignore + cursor += 2; + break; + case OC_SYSKILLBSMT: + // Kill channel i guess + if (pSampleHeader[cursor + 1] != channel) + StopChannel(pSampleHeader[cursor + 1]); + cursor += 2; + break; + case OC_SEQSTARTVOICE: + // Weird lookup opcode thing + WORD temp; + WORD realOpcode; + + temp = pSampleHeader[cursor + 2] << 8 | pSampleHeader[cursor + 3]; + realOpcode = *(pSampleHeaders + temp) + 0x200; + info("OpenSndVoyager::sndPlay Sequenced realOpcode: %X", realOpcode); + + sndPlay(realOpcode); + cursor += 4; + break; + case OC_CHANNELATTEN: + // Ignore for now + cursor += 2; + break; + case OC_SETMUSICTEMPO: + // Ignore for now + cursor += 2; + break; + case OC_LOCALTEMPO: + // Ignore for now + cursor += 2; + break; + case OC_SET_LUP_CNTL: + // Ignore for now + cursor += 2; + break; + case OC_SYSATTENDELTA: + // Ignore for now + // 1 Channel + // 2 Delta + cursor += 3; + break; + case OC_TEST_LUPC_JMP: + // Ignore for now + cursor += 2; + break; + case OC_SETGLOBALVAR: + // Ignore for now + cursor += 1; + break; + case OC_GETMUSICTEMPO: + // Ignore for now + cursor += 1; + break; + case OC_SETOCTOFF: + // Ignore for now + cursor += 2; + break; + case OC_SETNOTEOFF: + // Ignore for now + cursor += 2; + break; + case OC_SIGNEDATTEN: + // Ignore for now + // 1 channel + // 2+3 relative volume + cursor += 4; + break; + case OC_STRING_JSR: + // Ignore for now + cursor += 3; + break; + case OC_RANDOMDURATION: + // Ignore for now + cursor += 2; + break; + case OC_EOS: + // Stop + parsing = FALSE; + break; + default: + // Dunno + info("OpenSndVoyager::sndPlay Dunno OPCODE! code: %02X", pSampleHeader[cursor]); + // opcode + if (pSampleHeader[cursor] >= OC_SET_LUP_CNTL && pSampleHeader[cursor] <= OC_DIAGNOSTIC) + { + cursor += 1; + } + // not an opcode + else + { + AddSampleToChannel(channel, sample, pSampleHeader[cursor], level); + cursor += 2; + } + + break; + } + } + + qSize = channelBuffer[channel].qSamples.size(); + + if (qSize > 0) + { + if (!levelUsed) + channelBuffer[channel].qSamples[qSize - 1].level += level; + + channelBuffer[channel].loop = loop; + SetupChannel(channel); + PlayChannel(channel); + } +} \ No newline at end of file diff --git a/OpenSndVoyager/src/OpenSndVoyager.h b/OpenSndVoyager/src/OpenSndVoyager.h new file mode 100644 index 0000000..2562424 --- /dev/null +++ b/OpenSndVoyager/src/OpenSndVoyager.h @@ -0,0 +1,164 @@ +/* +* Created by Harm for TeknoParrot +* This file is part of the OpenParrot project - https://teknoparrot.com / https://github.com/teknogods +* +* See LICENSE and MENTIONS in the root of the source tree for information +* regarding licensing. +*/ + +#pragma once + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#define CHECK_HR(exp) { HRESULT hr = exp; if (FAILED(hr)) { info("failed %s: %08x\n", #exp, hr); abort(); } } + +#define CHANNELS 0x21 +#define SAMPLES 266 +#define MUTE_MUSIC TRUE + +// Opcodes (0x0804e120) +#define OC_SET_LUP_CNTL 0X80 // 0x8048E80 uint set_lup_cntl(int param_1) +#define OC_TEST_LUPC_JMP 0X81 // 0x8048E9C uint test_lupc_jmp(int param_1) +#define OC_START_VOICE 0X82 // 0x8048EF4 uint start_voice(int pVoice) +#define OC_SETGATETHRESHOLD 0X83 // 0x8048F18 uint setGateThreshold(int param_1) +#define OC_STRING_BRANCH 0X84 // 0x8048F34 uint string_branch(int param_1) +#define OC_STRING_JSR 0X85 // 0x8048FD8 uint string_jsr(int param_1) +#define OC_STRING_RTS 0X86 // 0x8049004 uint string_rts(uint * param_1) +#define OC_SETOCTOFF 0X87 // 0x8049020 uint setOctOff(int param_1) +#define OC_EOS 0X88 // 0x8048ED0 uint eos(uint * param_1) +#define OC_REST 0X89 // 0x804904C uint rest(int param_1) +#define OC_TOGGLESYNC 0X8A // 0x8049078 uint togglesync(void) +#define OC_NEWNOTE 0X8B // 0x804908C uint newnote(void) +#define OC_SETNOTEOFF 0X8C // 0x80490A0 uint setNoteOff(int param_1) +#define OC_SETPAN 0X8D // 0x80490BC uint SetPan(void) +#define OC_GETNOTEOFF 0X8E // 0x80490D0 uint getNoteOff(void) +#define OC_SETSTEPMODE 0X8F // 0x80490E4 uint SetStepMode(void) +#define OC_SETPATCH 0X90 // 0x80490F8 uint setpatch(int param_1) +#define OC_SETPDELT 0X91 // 0x8049114 uint setPDelt(void) +#define OC_CLRPDELT 0X92 // 0x8049128 uint clrPDelt(void) +#define OC_SETFRAC 0X93 // 0x804913C uint setFrac(void) +#define OC_SETTEMPOMODE 0X94 // 0x8049150 uint setTempoMode(void) +#define OC_SETVIBRATO 0X95 // 0x8049164 uint setVibrato(void) +#define OC_DOAUTONOTRIG 0X96 // 0x8049178 uint doAutoNoTrig(void) +#define OC_MASTEROPLATTEN 0X97 // 0x804918C uint masterOPLatten(void) +#define OC_SETAUTO 0X98 // 0x80491A0 uint setAuto(void) +#define OC_DOAUTO 0X99 // 0x80491B4 uint doAuto(void) +#define OC_CHECKKEY 0X9A // 0x80491C8 uint checkKey(void) +#define OC_RNDVOICE 0X9B // 0x80491DC uint rndVoice(void) +#define OC_INITSYNC 0X9C // 0x80491F0 uint initsync(void) +#define OC_WAITSYNC 0X9D // 0x8049204 uint waitsync(void) +#define OC_SETATTEN 0X9E // 0x804926C uint setAtten(uint * param_1) +#define OC_SETKEY 0X9F // 0x8049294 uint setKey(void) +#define OC_STAY 0XA0 // 0x80492A8 uint Stay(int param_1) +#define OC_RETRIGGER 0XA1 // 0x80492CC uint retrigger(void) +#define OC_RNDSTRJMP 0XA2 // 0x80492E0 uint RndStrJmp(void) +#define OC_GLOBALKEYSWITCH 0XA3 // 0x80492F4 uint globalKeySwitch(void) +#define OC_SETGATEPER 0XA4 // 0x8049308 uint setGatePer(void) +#define OC_SETPRIORITY 0XA5 // 0x804931C uint setPriority(int param_1) +#define OC_SETMUSICTEMPO 0XA6 // 0x8049338 uint setmusicTempo(int param_1) +#define OC_SETPITCHOFFSET 0XA7 // 0x8049354 uint SetPitchOffset(int param_1) +#define OC_DYNAMICPAN 0XA8 // 0x8049370 uint DynamicPan(void) +#define OC_LOCALTEMPO 0XA9 // 0x8049384 uint LocalTempo(int param_1) +#define OC_PUTTICKET 0XAA // 0x80493B8 uint putTicket(void) +#define OC_CHANNELATTEN 0XAB // 0x80493CC uint ChannelAtten(uint * param_1) +#define OC_SYSATTEN 0XAC // 0x80493F4 uint sysAtten(void) +#define OC_SYSATTENDELTA 0XAD // 0x804942C uint sysAttenDelta(int param_1) +#define OC_ATTRACT 0XAE // 0x8049484 uint Attract(void) +#define OC_INCGLOBALVAR 0XAF // 0x8049498 uint incGlobalVar(void) +#define OC_SIGNEDATTEN 0XB0 // 0x80494AC uint signedAtten(uint * param_1) +#define OC_SETGLOBALVAR 0XB1 // 0x80494E0 uint setGlobalVar(void) +#define OC_STRJSRINC 0XB2 // 0x80494F4 uint StrJsrInc(void) +#define OC_SYSKILLBSMT 0XB3 // 0x8049508 uint sysKillBSMT(int param_1) +#define OC_CONSTARTVOICE 0XB4 // 0x8049558 uint ConStartVoice(void) +#define OC_SETRNDFREQ 0XB5 // 0x804956C uint setRndFreq(void) +#define OC_STARTPOINTER 0XB6 // 0x8049580 uint StartPointer(void) +#define OC_RNDSTRJSR 0XB7 // 0x8049594 uint RndStrJsr(void) +#define OC_SYSKEY 0XB8 // 0x80495A8 uint sysKey(void) +#define OC_SYSKEYDELTA 0XB9 // 0x80495BC uint sysKeyDelta(void) +#define OC_GETMUSICTEMPO 0XBA // 0x80495D8 uint getmusicTempo(int param_1) +#define OC_SNOP 0XBB // 0x80495FC uint snop(void) +#define OC_RANDOMDURATION 0XBC // 0x8049610 uint RandomDuration(void) +#define OC_TEMPODELTA 0XBD // 0x8049624 uint tempodelta(void) +#define OC_GLOBALTEMPODELTA 0XBE // 0x8049638 uint GlobalTempoDelta(void) +#define OC_UPDATEGLOBALTEMPO 0XBF // 0x804964C uint UpdateGlobalTempo(void) +#define OC_SETMUSICLEVEL 0XC0 // 0x8049660 uint setMusicLevel(void) +#define OC_MUSICLEVELSTART 0XC1 // 0x8049674 uint MusicLevelStart(void) +#define OC_PLAYQ 0XC2 // 0x8049688 uint playQ(void) +#define OC_SYSKILLCONDUCT 0XC3 // 0x804969C uint sysKillConduct(void) +#define OC_SETPITCHBENDRANGE 0XC4 // 0x80496B0 uint SetPitchBendRange(void) +#define OC_SETENVELOPE 0XC5 // 0x80496C4 uint SetEnvelope(int param_1) +#define OC_MUSICKEYDELTA 0XC6 // 0x8049708 uint MusicKeyDelta(void) +#define OC_SETKEYCHASEMODE 0XC7 // 0x804971C uint setKeyChaseMode(void) +#define OC_SETSYSPRIORITY 0XC8 // 0x8049730 uint setSysPriority(void) +#define OC_SETVELOCITY 0XC9 // 0x8049744 uint setVelocity(void) +#define OC_GLOBALVARTOTEMPO 0XCA // 0x8049758 uint GlobalVarToTempo(void) +#define OC_ANDORB 0XCB // 0x804976C uint ANDORB(void) +#define OC_ORORB 0XCC // 0x8049780 uint ORORB(void) +#define OC_SETPITCHBEND 0XCD // 0x8049794 uint SetPitchBend(void) +#define OC_FLUSHQ 0XCE // 0x80497A8 uint FlushQ(void) +#define OC_SETALGORITHM 0XCF // 0x80497BC uint setAlgorithm(void) +#define OC_ANDORA 0XD0 // 0x80497D0 uint ANDORA(void) +#define OC_ORORA 0XD1 // 0x80497E4 uint ORORA(void) +#define OC_EOS_2 0XD2 // 0x8048ED0 uint eos(uint * param_1) +#define OC_EOS_3 0XD3 // 0x8048ED0 uint eos(uint * param_1) +#define OC_FORK 0XD4 // 0x80497F8 uint FORK(void) +#define OC_TEMPOTOGLOBALVAR 0XD5 // 0x804980C uint TempoToGlobalVar(void) +#define OC_SETMULTISAMPLE 0XD6 // 0x8049820 uint SetMultiSample(void) +#define OC_EOS_4 0XD7 // 0x8048ED0 uint eos(uint * param_1) +#define OC_RNDNOTE 0XD8 // 0x8049834 uint RndNote(void) +#define OC_INCCOINCOUNT 0XD9 // 0x804985C uint IncCoinCount(void) +#define OC_INCTICKETCOUNT 0XDA // 0x8049848 uint IncTicketCount(void) +#define OC_SETWORDPOINTER 0XDB // 0x8049870 uint SetWordPointer(void) +#define OC_INCMUSICLEVEL 0XDC // 0x8049884 uint IncMusicLevel(void) +#define OC_DECMUSICLEVEL 0XDD // 0x8049898 uint DecMusicLevel(void) +#define OC_SWITCHSOUNDTABLE 0XDE // 0x80498AC uint SwitchSoundTable(void) +#define OC_IFTHEN 0XDF // 0x80498C0 uint IfThen(void) +#define OC_SEQSTARTVOICE 0XE0 // 0x80498D4 uint SeqStartVoice(int param_1) +#define OC_DIAGNOSTIC 0XE1 // 0x804999C uint Diagnostic(void) + +class XA2Callback : public IXAudio2VoiceCallback +{ +public: + void __stdcall OnVoiceProcessingPassStart(UINT32 BytesRequired) override + { + } + + void __stdcall OnVoiceProcessingPassEnd() override + { + } + + void __stdcall OnStreamEnd() override + { + } + + void __stdcall OnBufferStart(void*) override + { + } + + void __stdcall OnLoopEnd(void*) override + { + } + + void __stdcall OnVoiceError(void*, HRESULT) override + { + } + + void __stdcall OnBufferEnd(void* cxt) override; + +public: + BYTE channel; +}; + +__declspec(dllexport) void snd_init_new(DWORD level); +__declspec(dllexport) void snd_code_always(INT code); +__declspec(dllexport) void sndPlay(INT code); + +// Declarations +struct BUFFER; +struct qSample; +void ResetChannel(BYTE channel); +void PlayChannelNext(BYTE channel); +DWORD SpeedToSampleRate(BYTE speed); +void StopChannel(BYTE channel); \ No newline at end of file diff --git a/OpenSndVoyager/src/OpenSndVoyager.rc b/OpenSndVoyager/src/OpenSndVoyager.rc new file mode 100644 index 0000000000000000000000000000000000000000..b0ef2dfb3d0858fe5ca337acffa1f30b7f37a4a8 GIT binary patch literal 5292 zcmdUzTW=CU6vxlAiQi$RFE*N%US53cg<>Oxrd*Aj zK~2_dhS{AtbMCj{$M;R!w8&0uU>|L4BbzWTZOU4QwTa!@gn*UqfM>LKrStJynNn*5&FJ}Wie1AXyOyeDuM=E$n(WnRaZXlZ0$ zkbjDHq=yz#zvcHBsSl7-`lztJ&6u~yuWfMW^y|;1^BHhJ?=IkEK|FPJ1^YT)$sEEQWlFz(qAUgcw| zN&K{lt^+7{@va(=@P6Zo7M^T@;|w3}a;nbxbw{&z-?8(aS-sGOt2af-ukZg! zeyt2?K?%Oq!{4|Za*y9#@YQEsJx>W=>DyX!TWbScd)BVC%x>i!XTpTSeIE9toHpuh2hHdo05>1b_%P1SyajdZU{ zMv}5}$P@CCE$0R0S&sA^$Na``%Aw12gUfaw#p- + Get-Content .\OpenSndVoyager\src\OpenSndVoyager.rc | ForEach-Object { $_ -replace "1.0.0.0", $env:appveyor_build_version } | Set-Content .\OpenSndVoyager\src\OpenSndVoyager2.rc + + del .\OpenSndVoyager\src\OpenSndVoyager.rc + + mv .\OpenSndVoyager\src\OpenSndVoyager2.rc .\OpenSndVoyager\src\OpenSndVoyager.rc + +build: + project: OpenSndVoyager.sln + verbosity: minimal + +artifacts: +- path: build\bin\release\output\ + name: OpenSndVoyager +deploy: +- provider: GitHub + tag: OpenSndVoyager + release: $(APPVEYOR_BUILD_VERSION) + description: $(APPVEYOR_REPO_COMMIT_MESSAGE) + auth_token: + secure: a2B+6mDTHuBa0fw8nm739eGJIZBcZp0IenhKvvXvreLR6ZUoHg9pflMP8ahNUK6o + repository: teknogods/OpenSndVoyager + artifact: build\bin\release\OpenSndVoyager.zip + force_update: true diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..23b447f --- /dev/null +++ b/build.ps1 @@ -0,0 +1,3 @@ +Get-Content .\OpenSndVoyager\src\OpenSndVoyager.rc | ForEach-Object { $_ -replace "1.0.0.0", $APPVEYOR_BUILD_VERSION } | Set-Content .\OpenSndVoyager\src\OpenSndVoyager2.rc +del .\OpenSndVoyager\src\OpenSndVoyager.rc +mv .\OpenSndVoyager\src\OpenSndVoyager2.rc .\OpenSndVoyager\src\OpenSndVoyager.rc \ No newline at end of file diff --git a/premake5.bat b/premake5.bat new file mode 100644 index 0000000..fc462e1 --- /dev/null +++ b/premake5.bat @@ -0,0 +1,2 @@ +premake5 vs2019 +pause \ No newline at end of file diff --git a/premake5.exe b/premake5.exe new file mode 100644 index 0000000000000000000000000000000000000000..9048d51e09da5bde02e6337dcfaa603a2cebf292 GIT binary patch literal 1362432 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