From 852ee1c3556c09f35d264c934612845fe29c64bd Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Tue, 24 Sep 2013 21:21:56 +0200 Subject: [PATCH] Audio SDL plugin. Compile and run on the OpenPandora --- source/mupen64plus-audio-sdl/INSTALL | 26 + source/mupen64plus-audio-sdl/LICENSES | 369 ++++++ source/mupen64plus-audio-sdl/RELEASE | 109 ++ .../msvc11/mupen64plus-audio-sdl.vcxproj | 107 ++ .../msvc8/mupen64plus-audio-sdl.vcproj | 209 ++++ .../projects/unix/Makefile | 371 ++++++ source/mupen64plus-audio-sdl/src/main.c | 1008 +++++++++++++++++ source/mupen64plus-audio-sdl/src/main.h | 48 + .../src/osal_dynamiclib.h | 30 + .../src/osal_dynamiclib_unix.c | 37 + .../src/osal_dynamiclib_win32.c | 74 ++ source/mupen64plus-audio-sdl/src/volume.c | 88 ++ source/mupen64plus-audio-sdl/src/volume.h | 33 + 13 files changed, 2509 insertions(+) create mode 100644 source/mupen64plus-audio-sdl/INSTALL create mode 100644 source/mupen64plus-audio-sdl/LICENSES create mode 100644 source/mupen64plus-audio-sdl/RELEASE create mode 100644 source/mupen64plus-audio-sdl/projects/msvc11/mupen64plus-audio-sdl.vcxproj create mode 100644 source/mupen64plus-audio-sdl/projects/msvc8/mupen64plus-audio-sdl.vcproj create mode 100755 source/mupen64plus-audio-sdl/projects/unix/Makefile create mode 100755 source/mupen64plus-audio-sdl/src/main.c create mode 100755 source/mupen64plus-audio-sdl/src/main.h create mode 100644 source/mupen64plus-audio-sdl/src/osal_dynamiclib.h create mode 100644 source/mupen64plus-audio-sdl/src/osal_dynamiclib_unix.c create mode 100644 source/mupen64plus-audio-sdl/src/osal_dynamiclib_win32.c create mode 100644 source/mupen64plus-audio-sdl/src/volume.c create mode 100644 source/mupen64plus-audio-sdl/src/volume.h diff --git a/source/mupen64plus-audio-sdl/INSTALL b/source/mupen64plus-audio-sdl/INSTALL new file mode 100644 index 0000000..48986f1 --- /dev/null +++ b/source/mupen64plus-audio-sdl/INSTALL @@ -0,0 +1,26 @@ +Mupen64Plus-Audio-SDL INSTALL +----------------------------- + +This text file was written to explain the installation process of the +Mupen64Plus-Audio-SDL module. + +If this module is part of a Mupen64Plus source code bundle, the user should run +the "m64p_install.sh" script in the root of the unzipped bundle to install all +of the included modules in the bundle. + +If this module is a standalone source code release, you should build the library +from source code and install it via the makefile, like this: + +$ cd projects/unix +$ make all +$ sudo make install + +If you want to build the Mupen64Plus-Audio-SDL module for installation in a +home folder for a single user, you may build it like this (replacing + with your desired local installation path): + +$ cd projects/unix +$ make all +$ make install LIBDIR= + + diff --git a/source/mupen64plus-audio-sdl/LICENSES b/source/mupen64plus-audio-sdl/LICENSES new file mode 100644 index 0000000..ac42959 --- /dev/null +++ b/source/mupen64plus-audio-sdl/LICENSES @@ -0,0 +1,369 @@ +Mupen64Plus-audio-sdl LICENSE +----------------------------- + +Mupen64Plus-audio-sdl is licensed under the GNU General Public License version 2. + +The authors of Mupen64Plus are: + * Richard Goedeken (Richard42) + * John Chadwick (NMN) + * James Hood (Ebenblues) + * Scott Gorman (okaygo) + * Scott Knauert (Tillin9) + * Jesse Dean (DarkJezter) + * Louai Al-Khanji (slougi) + * Bob Forder (orbitaldecay) + * Jason Espinosa (hasone) + * Casualjames + * HyperHacker + * and others. + +Mupen64Plus is based on GPL-licensed source code from Mupen64 v0.5, originally written by: + * Hacktarux + * Dave2001 + * Zilmar + * Gregor Anich (Blight) + * Juha Luotio (JttL) + * and others. + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + diff --git a/source/mupen64plus-audio-sdl/RELEASE b/source/mupen64plus-audio-sdl/RELEASE new file mode 100644 index 0000000..ed489c1 --- /dev/null +++ b/source/mupen64plus-audio-sdl/RELEASE @@ -0,0 +1,109 @@ +SDL Audio plugin for Mupen64Plus +--------------------------------- + +Mupen64Plus-audio-sdl - v2.0 - July 4, 2013 +------------------------------------------- + - Add support for resampling with speexdsp library + - Add more resampling quality options + - Bugfix: Don't assume OSS is installed in all linux systems. + - Bugfix: Some combinations of VolumeSetLevel and VolumeMute caused VolumeGetString to return "Mute" when not muted + - Make SDL volume handling the default, since OSS is no longer included in the kernel. + - Minor refactoring of volume handling code. + - MS Visual Studio 2012 project files + - Makefile improvements + - support for ARM and MINGW architectures + - support for cross-compiling (MXE win32 builds under Unix) + +Mupen64Plus-audio-sdl v1.99.5 - March 10, 2012 +-------------------------------------------------- + - added version number to SDL-audio plugin config parameters, to support future changes + - updated audio plugin for new Mupen64plus 2.0 API versioning scheme + - makefile fixes and improvements + +Mupen64Plus-audio-sdl v1.99.4 - November 22, 2010 +-------------------------------------------------- + - Bugfix: Plugin should write default config values at startup time + - Bugfix: fixed fast-forward for banjo-kazooie and other games which was broken due to limitation in basic resampling algorithm + - many makefile fixes and improvements + +Mupen64Plus-audio-sdl v1.99.3 - February 13, 2010 +-------------------------------------------------- + - sync with core<-->plugin API change for RomOpen() + - bugfix: logical error in previous audio refactoring causing slowdown/lockup on loading savestate or re-initializing audio + - Makefile improvements: + - 'sdl-config --libs' can give "-Wl,-rpath", so plugin must be linked with CC instead of LD + - issue #257: added to makefile OS type GNU/kFreeBSD + +Mupen64Plus-audio-sdl v1.99.2 - January 6, 2010 +------------------------------------------------- + - new feature: Completely re-wrote buffering/synchronization code: + - Buffer parameters now work as advertised and all use the same units + - Bugfix: previous defaults and algorithm behavior caused audio choppiness on slower PCs + - Bugfix: maximum speed was previously limited to low value by constraints from primary buffer size + - bugfix: SDL volume control will always be used on systems without OSS support + - new feature: added MSVC8 project file, minor code refactoring to build in Windows + - Makefile improvements: + - throw error if OS/CPU not supported + - use DESTDIR in install/uninstall paths + - Allow user-specified CC/CXX/LD paths + +Mupen64Plus-audio-sdl v1.99.1 - December 14, 2009 +------------------------------------------------- + - Converted to new Mupen64Plus 2.0 API + - Code cleanup to remove non-standard data types + - Refactored build system to separate source and object files + - bugfix #269: jttl_audio segfaults on exit due to incorrectly ordered shutdown code + + Mupen64plus 1.5: + +Additional SDL modulation option for volume control. + +New Gtk GUI for plugin configuration. + +Improved no GUI support. + + Mupen64plus 1.4: + +Extended plugin API to allow all for runtime volume changes via OSS. + + 1.4: + +Use only standard frequency for higher compatibility + +Fast resample algorithm (use only integers) + +Slight improvements in buffer management : pausing audio when buffer underrun occur + + 1.2: + +Added possibility to swap channels + +Some more optimizations + +Calling RomOpen() is not required anymore. Plugin should now follow Zilmar's specs. + +Added test functions. + +Added support for config file + + 1.1.1: + +Fixed the bug that was causing terrible noise (thanks Law) + +Much more debugging data appears now if DEBUG is defined + +Few more error checks + + 1.1: + +Audio device is opened now with native byte ordering of the machine. Just + for compatibility (thanks Flea). + +Fixed possible double freeing bug (thanks Flea) + +Optimizations in AiLenChanged + +Fixed segmentation fault when changing rom. + +Syncronization redone + + 1.0.1.3: + +Smarter versioning. No more betas. + +More cleaning up done. + +Buffer underrun and overflow messages appear now at stderr (if DEBUG is + defined) + +Many things are now precalculated (this should bring a small performance + boost) + +Buffer underrun bug fixed. + +Segmentation fault when closing rom fixed (at least I think so) + + 1.0 beta 2: + +Makefile fixed to get rid of annoying warning messages + +Cleaned up some old code + +Default frequency set to 33600Hz (for Master Quest compatibility) + +Better syncronization (needs some work still though) + + 1.0 beta 1: + +First public release + + diff --git a/source/mupen64plus-audio-sdl/projects/msvc11/mupen64plus-audio-sdl.vcxproj b/source/mupen64plus-audio-sdl/projects/msvc11/mupen64plus-audio-sdl.vcxproj new file mode 100644 index 0000000..69233ab --- /dev/null +++ b/source/mupen64plus-audio-sdl/projects/msvc11/mupen64plus-audio-sdl.vcxproj @@ -0,0 +1,107 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {96969748-EA54-43FC-8103-A346E9AD98E7} + mupen64plusaudiosdl + Win32Proj + + + + DynamicLibrary + MultiByte + true + v110 + + + DynamicLibrary + MultiByte + v110 + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..\mupen64plus-core\src\api;..\..\..\mupen64plus-win32-deps\SDL-1.2.14\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + Default + + + ..\..\..\mupen64plus-win32-deps\SDL-1.2.14\lib\SDL.lib;%(AdditionalDependencies) + true + Windows + MachineX86 + + + + + ..\..\..\mupen64plus-core\src\api;..\..\..\mupen64plus-win32-deps\SDL-1.2.14\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + Default + + + ..\..\..\mupen64plus-win32-deps\SDL-1.2.14\lib\SDL.lib;%(AdditionalDependencies) + true + Windows + true + true + MachineX86 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/mupen64plus-audio-sdl/projects/msvc8/mupen64plus-audio-sdl.vcproj b/source/mupen64plus-audio-sdl/projects/msvc8/mupen64plus-audio-sdl.vcproj new file mode 100644 index 0000000..f8c94fb --- /dev/null +++ b/source/mupen64plus-audio-sdl/projects/msvc8/mupen64plus-audio-sdl.vcproj @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/mupen64plus-audio-sdl/projects/unix/Makefile b/source/mupen64plus-audio-sdl/projects/unix/Makefile new file mode 100755 index 0000000..518f4cc --- /dev/null +++ b/source/mupen64plus-audio-sdl/projects/unix/Makefile @@ -0,0 +1,371 @@ +#/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +# * Mupen64plus-audio-sdl - Makefile * +# * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * +# * Copyright (C) 2007-2009 Richard Goedeken * +# * Copyright (C) 2007-2008 Tillin9 * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU General Public License as published by * +# * the Free Software Foundation; either version 2 of the License, or * +# * (at your option) any later version. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU General Public License for more details. * +# * * +# * You should have received a copy of the GNU General Public License * +# * along with this program; if not, write to the * +# * Free Software Foundation, Inc., * +# * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * +# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +# Makefile for SDL Audio plugin in Mupen64plus + +# detect operation system +UNAME ?= $(shell uname -s) +OS := NONE +ifeq ("$(UNAME)","Linux") + OS = LINUX + SHARED = -shared + SO_EXTENSION = so +endif +ifeq ("$(UNAME)","linux") + OS = LINUX + SHARED = -shared + SO_EXTENSION = so +endif +ifneq ("$(filter GNU hurd,$(UNAME))","") + OS = LINUX + SHARED = -shared + SO_EXTENSION = so +endif +ifeq ("$(UNAME)","Darwin") + OS = OSX + SHARED = -bundle + SO_EXTENSION = dylib +endif +ifeq ("$(UNAME)","FreeBSD") + OS = FREEBSD + SHARED = -shared + SO_EXTENSION = so +endif +ifeq ("$(UNAME)","OpenBSD") + OS = FREEBSD + SHARED = -shared + SO_EXTENSION = so + $(warning OS type "$(UNAME)" not officially supported.') +endif +ifneq ("$(filter GNU/kFreeBSD kfreebsd,$(UNAME))","") + OS = LINUX + SHARED = -shared + SO_EXTENSION = so +endif +ifeq ("$(patsubst MINGW%,MINGW,$(UNAME))","MINGW") + OS = MINGW + SHARED = -shared + SO_EXTENSION = dll + PIC = 0 + NO_OSS = 1 +endif +ifeq ("$(OS)","NONE") + $(error OS type "$(UNAME)" not supported. Please file bug report at 'http://code.google.com/p/mupen64plus/issues') +endif + +# detect system architecture +HOST_CPU ?= $(shell uname -m) +NO_ASM ?= 1 +CPU := NONE +ifneq ("$(filter x86_64 amd64,$(HOST_CPU))","") + CPU := X86 + ifeq ("$(BITS)", "32") + ARCH_DETECTED := 64BITS_32 + PIC ?= 0 + else + ARCH_DETECTED := 64BITS + PIC ?= 1 + endif +endif +ifneq ("$(filter pentium i%86,$(HOST_CPU))","") + CPU := X86 + ARCH_DETECTED := 32BITS + PIC ?= 0 +endif +ifneq ("$(filter ppc macppc socppc powerpc,$(HOST_CPU))","") + CPU := PPC + ARCH_DETECTED := 32BITS + BIG_ENDIAN := 1 + PIC ?= 1 + $(warning Architecture "$(HOST_CPU)" not officially supported.') +endif +ifneq ("$(filter ppc64 powerpc64,$(HOST_CPU))","") + CPU := PPC + ARCH_DETECTED := 64BITS + BIG_ENDIAN := 1 + PIC ?= 1 + $(warning Architecture "$(HOST_CPU)" not officially supported.') +endif +ifneq ("$(filter arm%,$(HOST_CPU))","") + ifeq ("$(filter arm%b,$(HOST_CPU))","") + CPU := ARM + ARCH_DETECTED := 32BITS + CFLAGS += -mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp -mtune=cortex-a8 -fsigned-char + PIC ?= 1 + $(warning Architecture "$(HOST_CPU)" not officially supported.') + endif +endif +ifeq ("$(CPU)","NONE") + $(error CPU type "$(HOST_CPU)" not supported. Please file bug report at 'http://code.google.com/p/mupen64plus/issues') +endif + +# base CFLAGS, LDLIBS, and LDFLAGS +OPTFLAGS ?= -O3 +WARNFLAGS ?= -Wall +CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -ffast-math -fno-strict-aliasing -fvisibility=hidden -I../../src +LDFLAGS += $(SHARED) + +# Since we are building a shared library, we must compile with -fPIC on some architectures +# On 32-bit x86 systems we do not want to use -fPIC because we don't have to and it has a big performance penalty on this arch +ifeq ($(PIC), 1) + CFLAGS += -fPIC +else + CFLAGS += -fno-PIC +endif + +ifeq ($(BIG_ENDIAN), 1) + CFLAGS += -DM64P_BIG_ENDIAN +endif + +# tweak flags for 32-bit build on 64-bit system +ifeq ($(ARCH_DETECTED), 64BITS_32) + ifeq ($(OS), FREEBSD) + $(error Do not use the BITS=32 option with FreeBSD, use -m32 and -m elf_i386) + endif + CFLAGS += -m32 + LDFLAGS += -Wl,-m,elf_i386 +endif + +# set special flags per-system +ifeq ($(OS), LINUX) + LDLIBS += -ldl +endif +ifeq ($(OS), OSX) + # Select the proper SDK + # Also, SDKs are stored in a different location since XCode 4.3 + OSX_SDK ?= $(shell sw_vers -productVersion | cut -f1 -f2 -d .) + OSX_XCODEMAJ = $(shell xcodebuild -version | grep '[0-9]*\.[0-9]*' | cut -f2 -d ' ' | cut -f1 -d .) + OSX_XCODEMIN = $(shell xcodebuild -version | grep '[0-9]*\.[0-9]*' | cut -f2 -d ' ' | cut -f2 -d .) + OSX_XCODEGE43 = $(shell echo "`expr $(OSX_XCODEMAJ) \>= 4``expr $(OSX_XCODEMIN) \>= 3`") + ifeq ($(OSX_XCODEGE43), 11) + OSX_SYSROOT := /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs + else + OSX_SYSROOT := /Developer/SDKs + endif + + ifeq ($(CPU), X86) + ifeq ($(ARCH_DETECTED), 64BITS) + CFLAGS += -pipe -arch x86_64 -mmacosx-version-min=$(OSX_SDK) -isysroot $(OSX_SYSROOT)/MacOSX$(OSX_SDK).sdk + LDLIBS += -ldl + else + CFLAGS += -pipe -mmmx -msse -fomit-frame-pointer -arch i686 -mmacosx-version-min=$(OSX_SDK) -isysroot $(OSX_SYSROOT)/MacOSX$(OSX_SDK).sdk + LDLIBS += -ldl -read_only_relocs suppress + endif + endif +endif + +# test for presence of SDL +ifeq ($(origin SDL_CFLAGS) $(origin SDL_LDLIBS), undefined undefined) + SDL_CONFIG = $(CROSS_COMPILE)sdl-config + ifeq ($(shell which $(SDL_CONFIG) 2>/dev/null),) + $(error No SDL development libraries found!) + endif + SDL_CFLAGS += $(shell $(SDL_CONFIG) --cflags) + SDL_LDLIBS += $(shell $(SDL_CONFIG) --libs) +endif +CFLAGS += $(SDL_CFLAGS) +LDLIBS += $(SDL_LDLIBS) + +# test for essential build dependencies +ifeq ($(origin PKG_CONFIG), undefined) + PKG_CONFIG = $(CROSS_COMPILE)pkg-config + ifeq ($(shell which $(PKG_CONFIG) 2>/dev/null),) + $(error $(PKG_CONFIG) not found) + endif +endif + +# test for presence of speexdsp +ifneq ($(NO_SPEEX), 1) + ifeq ($(origin SPEEX_CFLAGS) $(origin SPEEX_LDLIBS), undefined undefined) + ifneq ($(strip $(shell $(PKG_CONFIG) speexdsp --modversion 2> /dev/null)),) + # set speexdsp flags and libraries + SPEEX_CFLAGS += $(shell $(PKG_CONFIG) speexdsp --cflags) -DUSE_SPEEX + SPEEX_LDLIBS += $(shell $(PKG_CONFIG) speexdsp --libs) + else + # warn user + $(warning No libspeexdsp development libraries found. Mupen64plus-sdl-audio will be built without speex-* resampler.) + endif + else + SPEEX_CFLAGS += -DUSE_SPEEX + endif + CFLAGS += $(SPEEX_CFLAGS) + LDLIBS += $(SPEEX_LDLIBS) +endif + +# test for presence of libsamplerate +ifneq ($(NO_SRC), 1) + ifeq ($(origin SRC_CFLAGS) $(origin SRC_LDLIBS), undefined undefined) + ifneq ($(strip $(shell $(PKG_CONFIG) samplerate --modversion 2> /dev/null)),) + # set libsamplerate flags and libraries + SRC_CFLAGS += $(shell $(PKG_CONFIG) samplerate --cflags) -DUSE_SRC + SRC_LDLIBS += $(shell $(PKG_CONFIG) samplerate --libs) + else + $(warning No libsamplerate development libraries found. Mupen64plus-sdl-audio will be built without src-* resampler.) + endif + else + SRC_CFLAGS += -DUSE_SRC + endif + CFLAGS += $(SRC_CFLAGS) + LDLIBS += $(SRC_LDLIBS) +endif + +# test for the presence of OSS +ifneq ($(wildcard /dev/mixer),) + ifneq ($(NO_OSS), 1) + CFLAGS += -DHAS_OSS_SUPPORT + endif +endif + +# set mupen64plus core API header path +ifneq ("$(APIDIR)","") + CFLAGS += "-I$(APIDIR)" +else + TRYDIR = ../../../mupen64plus-core/src/api + ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","") + CFLAGS += -I$(TRYDIR) + else + TRYDIR = /usr/local/include/mupen64plus + ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","") + CFLAGS += -I$(TRYDIR) + else + TRYDIR = /usr/include/mupen64plus + ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","") + CFLAGS += -I$(TRYDIR) + else + $(error Mupen64Plus API header files not found! Use makefile parameter APIDIR to force a location.) + endif + endif + endif +endif + +# reduced compile output when running make without V=1 +ifneq ($(findstring $(MAKEFLAGS),s),s) +ifndef V + Q_CC = @echo ' CC '$@; + Q_LD = @echo ' LD '$@; +endif +endif + +# set base program pointers and flags +CC = $(CROSS_COMPILE)gcc +RM ?= rm -f +INSTALL ?= install +MKDIR ?= mkdir -p +COMPILE.c = $(Q_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c +LINK.o = $(Q_LD)$(CC) $(CFLAGS) $(LDFLAGS) $(TARGET_ARCH) + +# set special flags for given Makefile parameters +ifeq ($(DEBUG),1) + CFLAGS += -g + INSTALL_STRIP_FLAG ?= +else + ifneq ($(OS),OSX) + INSTALL_STRIP_FLAG ?= -s + endif +endif + +# set installation options +ifeq ($(PREFIX),) + PREFIX := /usr/local +endif +ifeq ($(LIBDIR),) + LIBDIR := $(PREFIX)/lib +endif +ifeq ($(PLUGINDIR),) + PLUGINDIR := $(LIBDIR)/mupen64plus +endif + +SRCDIR = ../../src +OBJDIR = _obj$(POSTFIX) + +# list of source files to compile +SOURCE = \ + $(SRCDIR)/main.c \ + $(SRCDIR)/volume.c + +ifeq ($(OS),MINGW) +SOURCE += $(SRCDIR)/osal_dynamiclib_win32.c +else +SOURCE += $(SRCDIR)/osal_dynamiclib_unix.c +endif + +# generate a list of object files build, make a temporary directory for them +OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(filter %.c, $(SOURCE))) +OBJDIRS = $(dir $(OBJECTS)) +$(shell $(MKDIR) $(OBJDIRS)) + +# build targets +TARGET = mupen64plus-audio-sdl$(POSTFIX).$(SO_EXTENSION) + +targets: + @echo "Mupen64Plus-audio-sdl makefile. " + @echo " Targets:" + @echo " all == Build Mupen64Plus SDL audio plugin" + @echo " clean == remove object files" + @echo " rebuild == clean and re-build all" + @echo " install == Install Mupen64Plus SDL audio plugin" + @echo " uninstall == Uninstall Mupen64Plus SDL audio plugin" + @echo " Options:" + @echo " BITS=32 == build 32-bit binaries on 64-bit machine" + @echo " APIDIR=path == path to find Mupen64Plus Core headers" + @echo " OPTFLAGS=flag == compiler optimization (default: -O3 -flto)" + @echo " WARNFLAGS=flag == compiler warning levels (default: -Wall)" + @echo " PIC=(1|0) == Force enable/disable of position independent code" + @echo " NO_SRC=1 == build without libsamplerate; disables src-* high-quality audio resampling" + @echo " NO_SPEEX=1 == build without libspeexdsp; disables speex-* high-quality audio resampling" + @echo " NO_OSS=1 == build without OSS; disables Open Sound System support" + @echo " POSTFIX=name == String added to the name of the the build (default: '')" + @echo " Install Options:" + @echo " PREFIX=path == install/uninstall prefix (default: /usr/local)" + @echo " LIBDIR=path == library prefix (default: PREFIX/lib)" + @echo " PLUGINDIR=path == path to install plugin libraries (default: LIBDIR/mupen64plus)" + @echo " DESTDIR=path == path to prepend to all installation paths (only for packagers)" + @echo " Debugging Options:" + @echo " DEBUG=1 == add debugging symbols" + @echo " V=1 == show verbose compiler output" + + +all: $(TARGET) + +install: $(TARGET) + $(INSTALL) -d "$(DESTDIR)$(PLUGINDIR)" + $(INSTALL) -m 0644 $(INSTALL_STRIP_FLAG) $(TARGET) "$(DESTDIR)$(PLUGINDIR)" + +uninstall: + $(RM) "$(DESTDIR)$(PLUGINDIR)/$(TARGET)" + +clean: + $(RM) -r $(OBJDIR) $(TARGET) + +rebuild: clean all + +# build dependency files +CFLAGS += -MD +-include $(OBJECTS:.o=.d) + +# standard build rules +$(OBJDIR)/%.o: $(SRCDIR)/%.c + $(COMPILE.c) -o $@ $< + +$(TARGET): $(OBJECTS) + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +.PHONY: all clean install uninstall targets diff --git a/source/mupen64plus-audio-sdl/src/main.c b/source/mupen64plus-audio-sdl/src/main.c new file mode 100755 index 0000000..e80517e --- /dev/null +++ b/source/mupen64plus-audio-sdl/src/main.c @@ -0,0 +1,1008 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-sdl-audio - main.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007-2009 Richard Goedeken * + * Copyright (C) 2007-2008 Ebenblues * + * Copyright (C) 2003 JttL * + * Copyright (C) 2002 Hacktarux * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include + +#include +#include + +#ifdef USE_SRC +#include +#endif +#ifdef USE_SPEEX +#include +#endif + +#define M64P_PLUGIN_PROTOTYPES 1 +#include "m64p_types.h" +#include "m64p_plugin.h" +#include "m64p_common.h" +#include "m64p_config.h" + +#include "main.h" +#include "volume.h" +#include "osal_dynamiclib.h" + +/* Default start-time size of primary buffer (in equivalent output samples). + This is the buffer where audio is loaded after it's extracted from n64's memory. + This value must be larger than PRIMARY_BUFFER_TARGET */ +#define PRIMARY_BUFFER_SIZE 16384 + +/* this is the buffer fullness level (in equivalent output samples) which is targeted + for the primary audio buffer (by inserting delays) each time data is received from + the running N64 program. This value must be larger than the SECONDARY_BUFFER_SIZE. + Decreasing this value will reduce audio latency but requires a faster PC to avoid + choppiness. Increasing this will increase audio latency but reduce the chance of + drop-outs. The default value 10240 gives a 232ms maximum A/V delay at 44.1khz */ +#define PRIMARY_BUFFER_TARGET 10240 + +/* Size of secondary buffer, in output samples. This is the requested size of SDL's + hardware buffer, and the size of the mix buffer for doing SDL volume control. The + SDL documentation states that this should be a power of two between 512 and 8192. */ +#define SECONDARY_BUFFER_SIZE 8192 +/*SEB 2048 before*/ + +/* This sets default frequency what is used if rom doesn't want to change it. + Probably only game that needs this is Zelda: Ocarina Of Time Master Quest + *NOTICE* We should try to find out why Demos' frequencies are always wrong + They tend to rely on a default frequency, apparently, never the same one ;)*/ +#define DEFAULT_FREQUENCY 33600 + +/* number of bytes per sample */ +#define N64_SAMPLE_BYTES 4 +#define SDL_SAMPLE_BYTES 4 + +/* volume mixer types */ +#define VOLUME_TYPE_SDL 1 +#define VOLUME_TYPE_OSS 2 + +/* local variables */ +static void (*l_DebugCallback)(void *, int, const char *) = NULL; +static void *l_DebugCallContext = NULL; +static int l_PluginInit = 0; +static int l_PausedForSync = 1; /* Audio is started in paused state after SDL initialization */ +static m64p_handle l_ConfigAudio; + +enum resampler_type { + RESAMPLER_TRIVIAL, +#ifdef USE_SRC + RESAMPLER_SRC, +#endif +#ifdef USE_SPEEX + RESAMPLER_SPEEX, +#endif +}; + +/* Read header for type definition */ +static AUDIO_INFO AudioInfo; +/* The hardware specifications we are using */ +static SDL_AudioSpec *hardware_spec; +/* Pointer to the primary audio buffer */ +static unsigned char *primaryBuffer = NULL; +static unsigned int primaryBufferBytes = 0; +/* Pointer to the mixing buffer for voume control*/ +static unsigned char *mixBuffer = NULL; +/* Position in buffer array where next audio chunk should be placed */ +static unsigned int buffer_pos = 0; +/* Audio frequency, this is usually obtained from the game, but for compatibility we set default value */ +static int GameFreq = DEFAULT_FREQUENCY; +/* timestamp for the last time that our audio callback was called */ +static unsigned int last_callback_ticks = 0; +/* SpeedFactor is used to increase/decrease game playback speed */ +static unsigned int speed_factor = 100; +// If this is true then left and right channels are swapped */ +static int SwapChannels = 0; +// Size of Primary audio buffer in equivalent output samples +static unsigned int PrimaryBufferSize = PRIMARY_BUFFER_SIZE; +// Fullness level target for Primary audio buffer, in equivalent output samples +static unsigned int PrimaryBufferTarget = PRIMARY_BUFFER_TARGET; +// Size of Secondary audio buffer in output samples +static unsigned int SecondaryBufferSize = SECONDARY_BUFFER_SIZE; +// Resample type +static enum resampler_type Resample = RESAMPLER_TRIVIAL; +// Resampler specific quality +static int ResampleQuality = 3; +// volume to scale the audio by, range of 0..100 +// if muted, this holds the volume when not muted +static int VolPercent = 80; +// how much percent to increment/decrement volume by +static int VolDelta = 5; +// the actual volume passed into SDL, range of 0..SDL_MIX_MAXVOLUME +static int VolSDL = SDL_MIX_MAXVOLUME; +// Muted or not +static int VolIsMuted = 0; +//which type of volume control to use +static int VolumeControlType = VOLUME_TYPE_SDL; + +static int OutputFreq; + +// Prototype of local functions +static void my_audio_callback(void *userdata, unsigned char *stream, int len); +static void InitializeAudio(int freq); +static void ReadConfig(void); +static void InitializeSDL(void); + +static int critical_failure = 0; + +/* definitions of pointers to Core config functions */ +ptr_ConfigOpenSection ConfigOpenSection = NULL; +ptr_ConfigDeleteSection ConfigDeleteSection = NULL; +ptr_ConfigSaveSection ConfigSaveSection = NULL; +ptr_ConfigSetParameter ConfigSetParameter = NULL; +ptr_ConfigGetParameter ConfigGetParameter = NULL; +ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL; +ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL; +ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat = NULL; +ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL; +ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL; +ptr_ConfigGetParamInt ConfigGetParamInt = NULL; +ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL; +ptr_ConfigGetParamBool ConfigGetParamBool = NULL; +ptr_ConfigGetParamString ConfigGetParamString = NULL; + +/* Global functions */ +static void DebugMessage(int level, const char *message, ...) +{ + char msgbuf[1024]; + va_list args; + + if (l_DebugCallback == NULL) + return; + + va_start(args, message); + vsprintf(msgbuf, message, args); + + (*l_DebugCallback)(l_DebugCallContext, level, msgbuf); + + va_end(args); +} + +/* Mupen64Plus plugin functions */ +EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context, + void (*DebugCallback)(void *, int, const char *)) +{ + ptr_CoreGetAPIVersions CoreAPIVersionFunc; + + int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion, bSaveConfig; + float fConfigParamsVersion = 0.0f; + + if (l_PluginInit) + return M64ERR_ALREADY_INIT; + + /* first thing is to set the callback function for debug info */ + l_DebugCallback = DebugCallback; + l_DebugCallContext = Context; + + /* attach and call the CoreGetAPIVersions function, check Config API version for compatibility */ + CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions"); + if (CoreAPIVersionFunc == NULL) + { + DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found."); + return M64ERR_INCOMPATIBLE; + } + + (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL); + if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000)) + { + DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)", + VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION)); + return M64ERR_INCOMPATIBLE; + } + + /* Get the core config function pointers from the library handle */ + ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection"); + ConfigDeleteSection = (ptr_ConfigDeleteSection) osal_dynlib_getproc(CoreLibHandle, "ConfigDeleteSection"); + ConfigSaveSection = (ptr_ConfigSaveSection) osal_dynlib_getproc(CoreLibHandle, "ConfigSaveSection"); + ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter"); + ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter"); + ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt"); + ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat"); + ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool"); + ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString"); + ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt"); + ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat"); + ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool"); + ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString"); + + if (!ConfigOpenSection || !ConfigDeleteSection || !ConfigSetParameter || !ConfigGetParameter || + !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString || + !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString) + return M64ERR_INCOMPATIBLE; + + /* ConfigSaveSection was added in Config API v2.1.0 */ + if (ConfigAPIVersion >= 0x020100 && !ConfigSaveSection) + return M64ERR_INCOMPATIBLE; + + /* get a configuration section handle */ + if (ConfigOpenSection("Audio-SDL", &l_ConfigAudio) != M64ERR_SUCCESS) + { + DebugMessage(M64MSG_ERROR, "Couldn't open config section 'Audio-SDL'"); + return M64ERR_INPUT_NOT_FOUND; + } + + /* check the section version number */ + bSaveConfig = 0; + if (ConfigGetParameter(l_ConfigAudio, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS) + { + DebugMessage(M64MSG_WARNING, "No version number in 'Audio-SDL' config section. Setting defaults."); + ConfigDeleteSection("Audio-SDL"); + ConfigOpenSection("Audio-SDL", &l_ConfigAudio); + bSaveConfig = 1; + } + else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION)) + { + DebugMessage(M64MSG_WARNING, "Incompatible version %.2f in 'Audio-SDL' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION); + ConfigDeleteSection("Audio-SDL"); + ConfigOpenSection("Audio-SDL", &l_ConfigAudio); + bSaveConfig = 1; + } + else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f) + { + /* handle upgrades */ + float fVersion = CONFIG_PARAM_VERSION; + ConfigSetParameter(l_ConfigAudio, "Version", M64TYPE_FLOAT, &fVersion); + DebugMessage(M64MSG_INFO, "Updating parameter set version in 'Audio-SDL' config section to %.2f", fVersion); + bSaveConfig = 1; + } + + /* set the default values for this plugin */ + ConfigSetDefaultFloat(l_ConfigAudio, "Version", CONFIG_PARAM_VERSION, "Mupen64Plus SDL Audio Plugin config parameter version number"); + ConfigSetDefaultInt(l_ConfigAudio, "DEFAULT_FREQUENCY", DEFAULT_FREQUENCY, "Frequency which is used if rom doesn't want to change it"); + ConfigSetDefaultBool(l_ConfigAudio, "SWAP_CHANNELS", 0, "Swaps left and right channels"); + ConfigSetDefaultInt(l_ConfigAudio, "PRIMARY_BUFFER_SIZE", PRIMARY_BUFFER_SIZE, "Size of primary buffer in output samples. This is where audio is loaded after it's extracted from n64's memory."); + ConfigSetDefaultInt(l_ConfigAudio, "PRIMARY_BUFFER_TARGET", PRIMARY_BUFFER_TARGET, "Fullness level target for Primary audio buffer, in equivalent output samples"); + ConfigSetDefaultInt(l_ConfigAudio, "SECONDARY_BUFFER_SIZE", SECONDARY_BUFFER_SIZE, "Size of secondary buffer in output samples. This is SDL's hardware buffer."); + ConfigSetDefaultString(l_ConfigAudio, "RESAMPLE", "trivial", "Audio resampling algorithm. src-sinc-best-quality, src-sinc-medium-quality, src-sinc-fastest, src-zero-order-hold, src-linear, speex-fixed-{10-0}, trivial"); + ConfigSetDefaultInt(l_ConfigAudio, "VOLUME_CONTROL_TYPE", VOLUME_TYPE_SDL, "Volume control type: 1 = SDL (only affects Mupen64Plus output) 2 = OSS mixer (adjusts master PC volume)"); + ConfigSetDefaultInt(l_ConfigAudio, "VOLUME_ADJUST", 5, "Percentage change each time the volume is increased or decreased"); + ConfigSetDefaultInt(l_ConfigAudio, "VOLUME_DEFAULT", 80, "Default volume when a game is started. Only used if VOLUME_CONTROL_TYPE is 1"); + + if (bSaveConfig && ConfigAPIVersion >= 0x020100) + ConfigSaveSection("Audio-SDL"); + + l_PluginInit = 1; + return M64ERR_SUCCESS; +} + +EXPORT m64p_error CALL PluginShutdown(void) +{ + if (!l_PluginInit) + return M64ERR_NOT_INIT; + + /* reset some local variables */ + l_DebugCallback = NULL; + l_DebugCallContext = NULL; + + /* make sure our buffer is freed */ + if (mixBuffer != NULL) + { + free(mixBuffer); + mixBuffer = NULL; + } + + l_PluginInit = 0; + return M64ERR_SUCCESS; +} + +EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities) +{ + /* set version info */ + if (PluginType != NULL) + *PluginType = M64PLUGIN_AUDIO; + + if (PluginVersion != NULL) + *PluginVersion = SDL_AUDIO_PLUGIN_VERSION; + + if (APIVersion != NULL) + *APIVersion = AUDIO_PLUGIN_API_VERSION; + + if (PluginNamePtr != NULL) + *PluginNamePtr = "Mupen64Plus SDL Audio Plugin"; + + if (Capabilities != NULL) + { + *Capabilities = 0; + } + + return M64ERR_SUCCESS; +} + +/* ----------- Audio Functions ------------- */ +EXPORT void CALL AiDacrateChanged( int SystemType ) +{ + int f = GameFreq; + + if (!l_PluginInit) + return; + + switch (SystemType) + { + case SYSTEM_NTSC: + f = 48681812 / (*AudioInfo.AI_DACRATE_REG + 1); + break; + case SYSTEM_PAL: + f = 49656530 / (*AudioInfo.AI_DACRATE_REG + 1); + break; + case SYSTEM_MPAL: + f = 48628316 / (*AudioInfo.AI_DACRATE_REG + 1); + break; + } + InitializeAudio(f); +} + + +EXPORT void CALL AiLenChanged( void ) +{ + unsigned int LenReg; + unsigned char *p; + unsigned int CurrLevel, CurrTime, ExpectedLevel, ExpectedTime; + + if (critical_failure == 1) + return; + if (!l_PluginInit) + return; + + LenReg = *AudioInfo.AI_LEN_REG; + p = AudioInfo.RDRAM + (*AudioInfo.AI_DRAM_ADDR_REG & 0xFFFFFF); + + if (buffer_pos + LenReg < primaryBufferBytes) + { + unsigned int i; + + SDL_LockAudio(); + for ( i = 0 ; i < LenReg ; i += 4 ) + { + + if(SwapChannels == 0) + { + // Left channel + primaryBuffer[ buffer_pos + i ] = p[ i + 2 ]; + primaryBuffer[ buffer_pos + i + 1 ] = p[ i + 3 ]; + + // Right channel + primaryBuffer[ buffer_pos + i + 2 ] = p[ i ]; + primaryBuffer[ buffer_pos + i + 3 ] = p[ i + 1 ]; + } else { + // Left channel + primaryBuffer[ buffer_pos + i ] = p[ i ]; + primaryBuffer[ buffer_pos + i + 1 ] = p[ i + 1 ]; + + // Right channel + primaryBuffer[ buffer_pos + i + 2 ] = p[ i + 2]; + primaryBuffer[ buffer_pos + i + 3 ] = p[ i + 3 ]; + } + } + buffer_pos += i; + SDL_UnlockAudio(); + } + else + { + DebugMessage(M64MSG_WARNING, "AiLenChanged(): Audio buffer overflow."); + } + + /* Now we need to handle synchronization, by inserting time delay to keep the emulator running at the correct speed */ + /* Start by calculating the current Primary buffer fullness in terms of output samples */ + CurrLevel = (unsigned int) (((long long) (buffer_pos/N64_SAMPLE_BYTES) * OutputFreq * 100) / (GameFreq * speed_factor)); + /* Next, extrapolate to the buffer level at the expected time of the next audio callback, assuming that the + buffer is filled at the same rate as the output frequency */ + CurrTime = SDL_GetTicks(); + ExpectedTime = last_callback_ticks + ((1000 * SecondaryBufferSize) / OutputFreq); + ExpectedLevel = CurrLevel; + if (CurrTime < ExpectedTime) + ExpectedLevel += (ExpectedTime - CurrTime) * OutputFreq / 1000; + /* If the expected value of the Primary Buffer Fullness at the time of the next audio callback is more than 10 + milliseconds ahead of our target buffer fullness level, then insert a delay now */ + DebugMessage(M64MSG_VERBOSE, "%03i New audio bytes: %i Time to next callback: %i Current/Expected buffer level: %i/%i", + CurrTime % 1000, LenReg, (int) (ExpectedTime - CurrTime), CurrLevel, ExpectedLevel); + if (ExpectedLevel >= PrimaryBufferTarget + OutputFreq / 100) + { + unsigned int WaitTime = (ExpectedLevel - PrimaryBufferTarget) * 1000 / OutputFreq; + DebugMessage(M64MSG_VERBOSE, " AiLenChanged(): Waiting %ims", WaitTime); + if (l_PausedForSync) + SDL_PauseAudio(0); + l_PausedForSync = 0; + SDL_Delay(WaitTime); + } + /* Or if the expected level of the primary buffer is less than the secondary buffer size + (ie, predicting an underflow), then pause the audio to let the emulator catch up to speed */ + else if (ExpectedLevel < SecondaryBufferSize) + { + DebugMessage(M64MSG_VERBOSE, " AiLenChanged(): Possible underflow at next audio callback; pausing playback"); + if (!l_PausedForSync) + SDL_PauseAudio(1); + l_PausedForSync = 1; + } + /* otherwise the predicted buffer level is within our tolerance, so everything is okay */ + else + { + if (l_PausedForSync) + SDL_PauseAudio(0); + l_PausedForSync = 0; + } +} + +EXPORT int CALL InitiateAudio( AUDIO_INFO Audio_Info ) +{ + if (!l_PluginInit) + return 0; + + AudioInfo = Audio_Info; + return 1; +} + +static int underrun_count = 0; + +#ifdef USE_SRC +static float *_src = NULL; +static unsigned int _src_len = 0; +static float *_dest = NULL; +static unsigned int _dest_len = 0; +static int error; +static SRC_STATE *src_state; +static SRC_DATA src_data; +#endif +#ifdef USE_SPEEX +SpeexResamplerState* spx_state = NULL; +static int error; +#endif + +static int resample(unsigned char *input, int input_avail, int oldsamplerate, unsigned char *output, int output_needed, int newsamplerate) +{ + int *psrc = (int*)input; + int *pdest = (int*)output; + int i = 0, j = 0; + +#ifdef USE_SPEEX + spx_uint32_t in_len, out_len; + if(Resample == RESAMPLER_SPEEX) + { + if(spx_state == NULL) + { + spx_state = speex_resampler_init(2, oldsamplerate, newsamplerate, ResampleQuality, &error); + if(spx_state == NULL) + { + memset(output, 0, output_needed); + return 0; + } + } + speex_resampler_set_rate(spx_state, oldsamplerate, newsamplerate); + in_len = input_avail / 4; + out_len = output_needed / 4; + + if ((error = speex_resampler_process_interleaved_int(spx_state, (const spx_int16_t *)input, &in_len, (spx_int16_t *)output, &out_len))) + { + memset(output, 0, output_needed); + return input_avail; // number of bytes consumed + } + return in_len * 4; + } +#endif +#ifdef USE_SRC + if(Resample == RESAMPLER_SRC) + { + // the high quality resampler needs more input than the samplerate ratio would indicate to work properly + if (input_avail > output_needed * 3 / 2) + input_avail = output_needed * 3 / 2; // just to avoid too much short-float-short conversion time + if (_src_len < input_avail*2 && input_avail > 0) + { + if(_src) free(_src); + _src_len = input_avail*2; + _src = malloc(_src_len); + } + if (_dest_len < output_needed*2 && output_needed > 0) + { + if(_dest) free(_dest); + _dest_len = output_needed*2; + _dest = malloc(_dest_len); + } + memset(_src,0,_src_len); + memset(_dest,0,_dest_len); + if(src_state == NULL) + { + src_state = src_new (ResampleQuality, 2, &error); + if(src_state == NULL) + { + memset(output, 0, output_needed); + return 0; + } + } + src_short_to_float_array ((short *) input, _src, input_avail/2); + src_data.end_of_input = 0; + src_data.data_in = _src; + src_data.input_frames = input_avail/4; + src_data.src_ratio = (float) newsamplerate / oldsamplerate; + src_data.data_out = _dest; + src_data.output_frames = output_needed/4; + if ((error = src_process (src_state, &src_data))) + { + memset(output, 0, output_needed); + return input_avail; // number of bytes consumed + } + src_float_to_short_array (_dest, (short *) output, output_needed/2); + return src_data.input_frames_used * 4; + } +#endif + // RESAMPLE == TRIVIAL + if (newsamplerate >= oldsamplerate) + { + int sldf = oldsamplerate; + int const2 = 2*sldf; + int dldf = newsamplerate; + int const1 = const2 - 2*dldf; + int criteria = const2 - dldf; + for (i = 0; i < output_needed/4; i++) + { + pdest[i] = psrc[j]; + if(criteria >= 0) + { + ++j; + criteria += const1; + } + else criteria += const2; + } + return j * 4; //number of bytes consumed + } + // newsamplerate < oldsamplerate, this only happens when speed_factor > 1 + for (i = 0; i < output_needed/4; i++) + { + j = i * oldsamplerate / newsamplerate; + pdest[i] = psrc[j]; + } + return j * 4; //number of bytes consumed +} + +static void my_audio_callback(void *userdata, unsigned char *stream, int len) +{ + int oldsamplerate, newsamplerate; + + if (!l_PluginInit) + return; + + /* mark the time, for synchronization on the input side */ + last_callback_ticks = SDL_GetTicks(); + + newsamplerate = OutputFreq * 100 / speed_factor; + oldsamplerate = GameFreq; + + if (buffer_pos > (unsigned int) (len * oldsamplerate) / newsamplerate) + { + int input_used; +#if defined(HAS_OSS_SUPPORT) + if (VolumeControlType == VOLUME_TYPE_OSS) + { + input_used = resample(primaryBuffer, buffer_pos, oldsamplerate, stream, len, newsamplerate); + } + else +#endif + { + input_used = resample(primaryBuffer, buffer_pos, oldsamplerate, mixBuffer, len, newsamplerate); + memset(stream, 0, len); + SDL_MixAudio(stream, mixBuffer, len, VolSDL); + } + memmove(primaryBuffer, &primaryBuffer[input_used], buffer_pos - input_used); + buffer_pos -= input_used; + DebugMessage(M64MSG_VERBOSE, "%03i my_audio_callback: used %i samples", + last_callback_ticks % 1000, len / SDL_SAMPLE_BYTES); + } + else + { + unsigned int SamplesNeeded = (len * oldsamplerate) / (newsamplerate * SDL_SAMPLE_BYTES); + unsigned int SamplesPresent = buffer_pos / N64_SAMPLE_BYTES; + underrun_count++; + DebugMessage(M64MSG_VERBOSE, "%03i Buffer underflow (%i). %i samples present, %i needed", + last_callback_ticks % 1000, underrun_count, SamplesPresent, SamplesNeeded); + memset(stream , 0, len); + } +} +EXPORT int CALL RomOpen(void) +{ + if (!l_PluginInit) + return 0; + + ReadConfig(); + InitializeAudio(GameFreq); + return 1; +} + +static void InitializeSDL(void) +{ + DebugMessage(M64MSG_INFO, "Initializing SDL audio subsystem..."); + + if(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER) < 0) + { + DebugMessage(M64MSG_ERROR, "Failed to initialize SDL audio subsystem; forcing exit.\n"); + critical_failure = 1; + return; + } + critical_failure = 0; + +} + +static void CreatePrimaryBuffer(void) +{ + unsigned int newPrimaryBytes = (unsigned int) ((long long) PrimaryBufferSize * GameFreq * speed_factor / + (OutputFreq * 100)) * N64_SAMPLE_BYTES; + if (primaryBuffer == NULL) + { + DebugMessage(M64MSG_VERBOSE, "Allocating memory for audio buffer: %i bytes.", newPrimaryBytes); + primaryBuffer = (unsigned char*) malloc(newPrimaryBytes); + memset(primaryBuffer, 0, newPrimaryBytes); + primaryBufferBytes = newPrimaryBytes; + } + else if (newPrimaryBytes > primaryBufferBytes) /* primary buffer only grows; there's no point in shrinking it */ + { + unsigned char *newPrimaryBuffer = (unsigned char*) malloc(newPrimaryBytes); + unsigned char *oldPrimaryBuffer = primaryBuffer; + SDL_LockAudio(); + memcpy(newPrimaryBuffer, oldPrimaryBuffer, primaryBufferBytes); + memset(newPrimaryBuffer + primaryBufferBytes, 0, newPrimaryBytes - primaryBufferBytes); + primaryBuffer = newPrimaryBuffer; + primaryBufferBytes = newPrimaryBytes; + SDL_UnlockAudio(); + free(oldPrimaryBuffer); + } +} + +static void InitializeAudio(int freq) +{ + SDL_AudioSpec *desired, *obtained; + + if(SDL_WasInit(SDL_INIT_AUDIO|SDL_INIT_TIMER) == (SDL_INIT_AUDIO|SDL_INIT_TIMER) ) + { + DebugMessage(M64MSG_VERBOSE, "InitializeAudio(): SDL Audio sub-system already initialized."); + SDL_PauseAudio(1); + SDL_CloseAudio(); + } + else + { + DebugMessage(M64MSG_VERBOSE, "InitializeAudio(): Initializing SDL Audio"); + DebugMessage(M64MSG_VERBOSE, "Primary buffer: %i output samples.", PrimaryBufferSize); + DebugMessage(M64MSG_VERBOSE, "Primary target fullness: %i output samples.", PrimaryBufferTarget); + DebugMessage(M64MSG_VERBOSE, "Secondary buffer: %i output samples.", SecondaryBufferSize); + InitializeSDL(); + } + if (critical_failure == 1) + return; + GameFreq = freq; // This is important for the sync + if(hardware_spec != NULL) free(hardware_spec); + + // Allocate space for SDL_AudioSpec + desired = malloc(sizeof(SDL_AudioSpec)); + obtained = malloc(sizeof(SDL_AudioSpec)); + + if(freq < 11025) OutputFreq = 11025; + else if(freq < 22050) OutputFreq = 22050; + else OutputFreq = 44100; + + desired->freq = OutputFreq; + + DebugMessage(M64MSG_VERBOSE, "Requesting frequency: %iHz.", desired->freq); + /* 16-bit signed audio */ + desired->format=AUDIO_S16SYS; + DebugMessage(M64MSG_VERBOSE, "Requesting format: %i.", desired->format); + /* Stereo */ + desired->channels=2; + /* reload these because they gets re-assigned from SDL data below, and InitializeAudio can be called more than once */ + PrimaryBufferSize = ConfigGetParamInt(l_ConfigAudio, "PRIMARY_BUFFER_SIZE"); + PrimaryBufferTarget = ConfigGetParamInt(l_ConfigAudio, "PRIMARY_BUFFER_TARGET"); + SecondaryBufferSize = ConfigGetParamInt(l_ConfigAudio, "SECONDARY_BUFFER_SIZE"); + desired->samples = SecondaryBufferSize; + /* Our callback function */ + desired->callback = my_audio_callback; + desired->userdata = NULL; + + /* Open the audio device */ + l_PausedForSync = 1; + if (SDL_OpenAudio(desired, obtained) < 0) + { + DebugMessage(M64MSG_ERROR, "Couldn't open audio: %s", SDL_GetError()); + critical_failure = 1; + return; + } + if (desired->format != obtained->format) + { + DebugMessage(M64MSG_WARNING, "Obtained audio format differs from requested."); + } + if (desired->freq != obtained->freq) + { + DebugMessage(M64MSG_WARNING, "Obtained frequency differs from requested."); + } + + /* desired spec is no longer needed */ + free(desired); + hardware_spec=obtained; + + /* allocate memory for audio buffers */ + OutputFreq = hardware_spec->freq; + SecondaryBufferSize = hardware_spec->samples; + if (PrimaryBufferTarget < SecondaryBufferSize) + PrimaryBufferTarget = SecondaryBufferSize; + if (PrimaryBufferSize < PrimaryBufferTarget) + PrimaryBufferSize = PrimaryBufferTarget; + if (PrimaryBufferSize < SecondaryBufferSize * 2) + PrimaryBufferSize = SecondaryBufferSize * 2; + CreatePrimaryBuffer(); + if (mixBuffer != NULL) + free(mixBuffer); + mixBuffer = (unsigned char*) malloc(SecondaryBufferSize * SDL_SAMPLE_BYTES); + + /* preset the last callback time */ + if (last_callback_ticks == 0) + last_callback_ticks = SDL_GetTicks(); + + DebugMessage(M64MSG_VERBOSE, "Frequency: %i", hardware_spec->freq); + DebugMessage(M64MSG_VERBOSE, "Format: %i", hardware_spec->format); + DebugMessage(M64MSG_VERBOSE, "Channels: %i", hardware_spec->channels); + DebugMessage(M64MSG_VERBOSE, "Silence: %i", hardware_spec->silence); + DebugMessage(M64MSG_VERBOSE, "Samples: %i", hardware_spec->samples); + DebugMessage(M64MSG_VERBOSE, "Size: %i", hardware_spec->size); + + /* set playback volume */ +#if defined(HAS_OSS_SUPPORT) + if (VolumeControlType == VOLUME_TYPE_OSS) + { + VolPercent = volGet(); + } + else +#endif + { + VolSDL = SDL_MIX_MAXVOLUME * VolPercent / 100; + } + +} +EXPORT void CALL RomClosed( void ) +{ + if (!l_PluginInit) + return; + if (critical_failure == 1) + return; + DebugMessage(M64MSG_VERBOSE, "Cleaning up SDL sound plugin..."); + + // Shut down SDL Audio output + SDL_PauseAudio(1); + SDL_CloseAudio(); + + // Delete the buffer, as we are done producing sound + if (primaryBuffer != NULL) + { + primaryBufferBytes = 0; + free(primaryBuffer); + primaryBuffer = NULL; + } + if (mixBuffer != NULL) + { + free(mixBuffer); + mixBuffer = NULL; + } + + // Delete the hardware spec struct + if(hardware_spec != NULL) free(hardware_spec); + hardware_spec = NULL; + + // Shutdown the respective subsystems + if(SDL_WasInit(SDL_INIT_AUDIO) != 0) SDL_QuitSubSystem(SDL_INIT_AUDIO); + if(SDL_WasInit(SDL_INIT_TIMER) != 0) SDL_QuitSubSystem(SDL_INIT_TIMER); +} + +EXPORT void CALL ProcessAList(void) +{ +} + +EXPORT void CALL SetSpeedFactor(int percentage) +{ + if (!l_PluginInit) + return; + if (percentage >= 10 && percentage <= 300) + speed_factor = percentage; + // we need a different size primary buffer to store the N64 samples when the speed changes + CreatePrimaryBuffer(); +} + +static void ReadConfig(void) +{ + const char *resampler_id; + + /* read the configuration values into our static variables */ + GameFreq = ConfigGetParamInt(l_ConfigAudio, "DEFAULT_FREQUENCY"); + SwapChannels = ConfigGetParamBool(l_ConfigAudio, "SWAP_CHANNELS"); + PrimaryBufferSize = ConfigGetParamInt(l_ConfigAudio, "PRIMARY_BUFFER_SIZE"); + PrimaryBufferTarget = ConfigGetParamInt(l_ConfigAudio, "PRIMARY_BUFFER_TARGET"); + SecondaryBufferSize = ConfigGetParamInt(l_ConfigAudio, "SECONDARY_BUFFER_SIZE"); + resampler_id = ConfigGetParamString(l_ConfigAudio, "RESAMPLE"); + VolumeControlType = ConfigGetParamInt(l_ConfigAudio, "VOLUME_CONTROL_TYPE"); + VolDelta = ConfigGetParamInt(l_ConfigAudio, "VOLUME_ADJUST"); + VolPercent = ConfigGetParamInt(l_ConfigAudio, "VOLUME_DEFAULT"); + + if (!resampler_id) { + Resample = RESAMPLER_TRIVIAL; + DebugMessage(M64MSG_WARNING, "Could not find RESAMPLE configuration; use trivial resampler"); + return; + } + if (strcmp(resampler_id, "trivial") == 0) { + Resample = RESAMPLER_TRIVIAL; + return; + } +#ifdef USE_SPEEX + if (strncmp(resampler_id, "speex-fixed-", strlen("speex-fixed-")) == 0) { + int i; + static const char *speex_quality[] = { + "speex-fixed-0", + "speex-fixed-1", + "speex-fixed-2", + "speex-fixed-3", + "speex-fixed-4", + "speex-fixed-5", + "speex-fixed-6", + "speex-fixed-7", + "speex-fixed-8", + "speex-fixed-9", + "speex-fixed-10", + }; + Resample = RESAMPLER_SPEEX; + for (i = 0; i < sizeof(speex_quality) / sizeof(*speex_quality); i++) { + if (strcmp(speex_quality[i], resampler_id) == 0) { + ResampleQuality = i; + return; + } + } + DebugMessage(M64MSG_WARNING, "Unknown RESAMPLE configuration %s; use speex-fixed-4 resampler", resampler_id); + ResampleQuality = 4; + return; + } +#endif +#ifdef USE_SRC + if (strncmp(resampler_id, "src-", strlen("src-")) == 0) { + Resample = RESAMPLER_SRC; + if (strcmp(resampler_id, "src-sinc-best-quality") == 0) { + ResampleQuality = SRC_SINC_BEST_QUALITY; + return; + } + if (strcmp(resampler_id, "src-sinc-medium-quality") == 0) { + ResampleQuality = SRC_SINC_MEDIUM_QUALITY; + return; + } + if (strcmp(resampler_id, "src-sinc-fastest") == 0) { + ResampleQuality = SRC_SINC_FASTEST; + return; + } + if (strcmp(resampler_id, "src-zero-order-hold") == 0) { + ResampleQuality = SRC_ZERO_ORDER_HOLD; + return; + } + if (strcmp(resampler_id, "src-linear") == 0) { + ResampleQuality = SRC_LINEAR; + return; + } + DebugMessage(M64MSG_WARNING, "Unknown RESAMPLE configuration %s; use src-sinc-medium-quality resampler", resampler_id); + ResampleQuality = SRC_SINC_MEDIUM_QUALITY; + return; + } +#endif + DebugMessage(M64MSG_WARNING, "Unknown RESAMPLE configuration %s; use trivial resampler", resampler_id); + Resample = RESAMPLER_TRIVIAL; +} + +// Returns the most recent ummuted volume level. +static int VolumeGetUnmutedLevel(void) +{ +#if defined(HAS_OSS_SUPPORT) + // reload volume if we're using OSS + if (!VolIsMuted && VolumeControlType == VOLUME_TYPE_OSS) + { + return volGet(); + } +#endif + + return VolPercent; +} + +// Sets the volume level based on the contents of VolPercent and VolIsMuted +static void VolumeCommit(void) +{ + int levelToCommit = VolIsMuted ? 0 : VolPercent; + +#if defined(HAS_OSS_SUPPORT) + if (VolumeControlType == VOLUME_TYPE_OSS) + { + //OSS mixer volume + volSet(levelToCommit); + } + else +#endif + { + VolSDL = SDL_MIX_MAXVOLUME * levelToCommit / 100; + } +} + +EXPORT void CALL VolumeMute(void) +{ + if (!l_PluginInit) + return; + + // Store the volume level in order to restore it later + if (!VolIsMuted) + VolPercent = VolumeGetUnmutedLevel(); + + // Toogle mute + VolIsMuted = !VolIsMuted; + VolumeCommit(); +} + +EXPORT void CALL VolumeUp(void) +{ + if (!l_PluginInit) + return; + + VolumeSetLevel(VolumeGetUnmutedLevel() + VolDelta); +} + +EXPORT void CALL VolumeDown(void) +{ + if (!l_PluginInit) + return; + + VolumeSetLevel(VolumeGetUnmutedLevel() - VolDelta); +} + +EXPORT int CALL VolumeGetLevel(void) +{ + return VolIsMuted ? 0 : VolumeGetUnmutedLevel(); +} + +EXPORT void CALL VolumeSetLevel(int level) +{ + if (!l_PluginInit) + return; + + //if muted, unmute first + VolIsMuted = 0; + + // adjust volume + VolPercent = level; + if (VolPercent < 0) + VolPercent = 0; + else if (VolPercent > 100) + VolPercent = 100; + + VolumeCommit(); +} + +EXPORT const char * CALL VolumeGetString(void) +{ + static char VolumeString[32]; + + if (VolIsMuted) + { + strcpy(VolumeString, "Mute"); + } + else + { + sprintf(VolumeString, "%i%%", VolPercent); + } + + return VolumeString; +} + diff --git a/source/mupen64plus-audio-sdl/src/main.h b/source/mupen64plus-audio-sdl/src/main.h new file mode 100755 index 0000000..b7cb3a7 --- /dev/null +++ b/source/mupen64plus-audio-sdl/src/main.h @@ -0,0 +1,48 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - main.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2008-2012 Tillin9, Richard42 * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* version info */ +#define SDL_AUDIO_PLUGIN_VERSION 0x020000 +#define AUDIO_PLUGIN_API_VERSION 0x020000 +#define CONFIG_API_VERSION 0x020100 +#define CONFIG_PARAM_VERSION 1.00 + +#define VERSION_PRINTF_SPLIT(x) (((x) >> 16) & 0xffff), (((x) >> 8) & 0xff), ((x) & 0xff) + +/* declarations of pointers to Core config functions */ +extern ptr_ConfigListSections ConfigListSections; +extern ptr_ConfigOpenSection ConfigOpenSection; +extern ptr_ConfigDeleteSection ConfigDeleteSection; +extern ptr_ConfigSaveSection ConfigSaveSection; +extern ptr_ConfigListParameters ConfigListParameters; +extern ptr_ConfigSaveFile ConfigSaveFile; +extern ptr_ConfigSetParameter ConfigSetParameter; +extern ptr_ConfigGetParameter ConfigGetParameter; +extern ptr_ConfigGetParameterHelp ConfigGetParameterHelp; +extern ptr_ConfigSetDefaultInt ConfigSetDefaultInt; +extern ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat; +extern ptr_ConfigSetDefaultBool ConfigSetDefaultBool; +extern ptr_ConfigSetDefaultString ConfigSetDefaultString; +extern ptr_ConfigGetParamInt ConfigGetParamInt; +extern ptr_ConfigGetParamFloat ConfigGetParamFloat; +extern ptr_ConfigGetParamBool ConfigGetParamBool; +extern ptr_ConfigGetParamString ConfigGetParamString; + diff --git a/source/mupen64plus-audio-sdl/src/osal_dynamiclib.h b/source/mupen64plus-audio-sdl/src/osal_dynamiclib.h new file mode 100644 index 0000000..daef154 --- /dev/null +++ b/source/mupen64plus-audio-sdl/src/osal_dynamiclib.h @@ -0,0 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - osal/dynamiclib.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2009 Richard Goedeken * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#if !defined(OSAL_DYNAMICLIB_H) +#define OSAL_DYNAMICLIB_H + +#include "m64p_types.h" + +void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName); + +#endif /* #define OSAL_DYNAMICLIB_H */ + diff --git a/source/mupen64plus-audio-sdl/src/osal_dynamiclib_unix.c b/source/mupen64plus-audio-sdl/src/osal_dynamiclib_unix.c new file mode 100644 index 0000000..b3b7ba5 --- /dev/null +++ b/source/mupen64plus-audio-sdl/src/osal_dynamiclib_unix.c @@ -0,0 +1,37 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-core - osal/dynamiclib_unix.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2009 Richard Goedeken * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include + +#include "m64p_types.h" +#include "osal_dynamiclib.h" + +void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName) +{ + if (pccProcedureName == NULL) + return NULL; + + return dlsym(LibHandle, pccProcedureName); +} + + diff --git a/source/mupen64plus-audio-sdl/src/osal_dynamiclib_win32.c b/source/mupen64plus-audio-sdl/src/osal_dynamiclib_win32.c new file mode 100644 index 0000000..685d717 --- /dev/null +++ b/source/mupen64plus-audio-sdl/src/osal_dynamiclib_win32.c @@ -0,0 +1,74 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-ui-console - osal_dynamiclib_win32.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2009 Richard Goedeken * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include + +#include "m64p_types.h" +#include "osal_dynamiclib.h" + +m64p_error osal_dynlib_open(m64p_dynlib_handle *pLibHandle, const char *pccLibraryPath) +{ + if (pLibHandle == NULL || pccLibraryPath == NULL) + return M64ERR_INPUT_ASSERT; + + *pLibHandle = LoadLibrary(pccLibraryPath); + + if (*pLibHandle == NULL) + { + char *pchErrMsg; + DWORD dwErr = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL); + fprintf(stderr, "LoadLibrary('%s') error: %s\n", pccLibraryPath, pchErrMsg); + LocalFree(pchErrMsg); + return M64ERR_INPUT_NOT_FOUND; + } + + return M64ERR_SUCCESS; +} + +void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName) +{ + if (pccProcedureName == NULL) + return NULL; + + return GetProcAddress(LibHandle, pccProcedureName); +} + +m64p_error osal_dynlib_close(m64p_dynlib_handle LibHandle) +{ + int rval = FreeLibrary(LibHandle); + + if (rval == 0) + { + char *pchErrMsg; + DWORD dwErr = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL); + fprintf(stderr, "FreeLibrary() error: %s\n", pchErrMsg); + LocalFree(pchErrMsg); + return M64ERR_INTERNAL; + } + + return M64ERR_SUCCESS; +} diff --git a/source/mupen64plus-audio-sdl/src/volume.c b/source/mupen64plus-audio-sdl/src/volume.c new file mode 100644 index 0000000..1c6e25c --- /dev/null +++ b/source/mupen64plus-audio-sdl/src/volume.c @@ -0,0 +1,88 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-sdl-audio - volume.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007-2008 Richard42 Ebenblues * + * Copyright (C) 2002 Hacktarux * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#if defined(HAS_OSS_SUPPORT) + +/* Sound volume functions. */ +#include +#include +#include +#include +#include /* close() */ +#include +#include +#include + +#include "volume.h" + +/* volSet + * Sets volume of left and right PCM channels to given percentage (0-100) value. + */ +void volSet(int percent) +{ + int ret, vol; + int mixerfd = open("/dev/mixer", O_RDONLY); + + if(mixerfd < 0) + { + perror("/dev/mixer"); + return; + } + + if(percent > 100) + percent = 100; + else if(percent < 0) + percent = 0; + + vol = (percent << 8) + percent; // set both left/right channels to same vol + ret = ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_PCM), &vol); + if(ret < 0) + perror("Setting PCM volume"); + + close(mixerfd); +} + +/* volGet + * Returns volume of PCM channel as a percentage (0-100). + * Returns 0 on error. + */ +int volGet(void) +{ + int vol, ret; + int mixerfd = open("/dev/mixer", O_RDONLY); + + if(mixerfd < 0) + { + perror("/dev/mixer"); + return 0; + } + + ret = ioctl(mixerfd, MIXER_READ(SOUND_MIXER_PCM), &vol); + if(ret < 0) + perror("Reading PCM volume"); + + close(mixerfd); + + return vol & 0xff; // just return the left channel +} + +#endif /* defined(HAS_OSS_SUPPORT) */ diff --git a/source/mupen64plus-audio-sdl/src/volume.h b/source/mupen64plus-audio-sdl/src/volume.h new file mode 100644 index 0000000..c1179cf --- /dev/null +++ b/source/mupen64plus-audio-sdl/src/volume.h @@ -0,0 +1,33 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - nogui.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007-2008 Richard42 Ebenblues * + * Copyright (C) 2002 Hacktarux * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* Sound volume functions. + */ + +#ifndef __VOLUME_H__ +#define __VOLUME_H__ + +void volSet(int); +int volGet(void); + +#endif // __VOLUME_H__ + -- 2.39.5