From 0d77f302926aee07d450c57eb93a61c52ec3528f Mon Sep 17 00:00:00 2001 From: pelya Date: Tue, 23 Nov 2010 17:19:40 +0200 Subject: [PATCH] Added OpenAL-Soft lib from git://repo.or.cz/openal-soft/android.git --- build.sh | 2 +- project/jni/application/src | 2 +- project/jni/openal/Android.mk | 25 + project/jni/openal/COPYING | 484 ++++ project/jni/openal/README | 20 + project/jni/openal/README-ANDROID | 51 + project/jni/openal/include/AL/al.h | 722 ++++++ project/jni/openal/include/AL/alc.h | 275 +++ project/jni/openal/include/AL/alext.h | 150 ++ project/jni/openal/include/AL/efx-creative.h | 3 + project/jni/openal/include/AL/efx.h | 758 ++++++ project/jni/openal/src/Alc/ALc.c | 2179 +++++++++++++++++ project/jni/openal/src/Alc/ALu.c | 1655 +++++++++++++ project/jni/openal/src/Alc/alcConfig.c | 338 +++ project/jni/openal/src/Alc/alcEcho.c | 193 ++ project/jni/openal/src/Alc/alcModulator.c | 200 ++ project/jni/openal/src/Alc/alcReverb.c | 1329 ++++++++++ project/jni/openal/src/Alc/alcRing.c | 131 + project/jni/openal/src/Alc/alcThread.c | 128 + project/jni/openal/src/Alc/android.c | 279 +++ project/jni/openal/src/Alc/bs2b.c | 201 ++ project/jni/openal/src/Alc/null.c | 176 ++ .../src/OpenAL32/Include/alAuxEffectSlot.h | 60 + .../openal/src/OpenAL32/Include/alBuffer.h | 39 + .../src/OpenAL32/Include/alDatabuffer.h | 33 + .../openal/src/OpenAL32/Include/alEffect.h | 83 + .../jni/openal/src/OpenAL32/Include/alError.h | 17 + .../openal/src/OpenAL32/Include/alFilter.h | 101 + .../openal/src/OpenAL32/Include/alListener.h | 24 + .../jni/openal/src/OpenAL32/Include/alMain.h | 497 ++++ .../openal/src/OpenAL32/Include/alSource.h | 115 + .../jni/openal/src/OpenAL32/Include/alState.h | 14 + .../jni/openal/src/OpenAL32/Include/alThunk.h | 42 + project/jni/openal/src/OpenAL32/Include/alu.h | 189 ++ .../jni/openal/src/OpenAL32/Include/bs2b.h | 109 + .../jni/openal/src/OpenAL32/alAuxEffectSlot.c | 523 ++++ project/jni/openal/src/OpenAL32/alBuffer.c | 1299 ++++++++++ .../jni/openal/src/OpenAL32/alDatabuffer.c | 656 +++++ project/jni/openal/src/OpenAL32/alEffect.c | 1376 +++++++++++ project/jni/openal/src/OpenAL32/alError.c | 47 + project/jni/openal/src/OpenAL32/alExtension.c | 329 +++ project/jni/openal/src/OpenAL32/alFilter.c | 431 ++++ project/jni/openal/src/OpenAL32/alListener.c | 484 ++++ project/jni/openal/src/OpenAL32/alSource.c | 2132 ++++++++++++++++ project/jni/openal/src/OpenAL32/alState.c | 661 +++++ project/jni/openal/src/OpenAL32/alThunk.c | 111 + project/jni/openal/src/config.h | 82 + project/jni/sdl_main/sdl_main.c | 5 + 48 files changed, 18758 insertions(+), 2 deletions(-) create mode 100644 project/jni/openal/Android.mk create mode 100644 project/jni/openal/COPYING create mode 100644 project/jni/openal/README create mode 100644 project/jni/openal/README-ANDROID create mode 100644 project/jni/openal/include/AL/al.h create mode 100644 project/jni/openal/include/AL/alc.h create mode 100644 project/jni/openal/include/AL/alext.h create mode 100644 project/jni/openal/include/AL/efx-creative.h create mode 100644 project/jni/openal/include/AL/efx.h create mode 100644 project/jni/openal/src/Alc/ALc.c create mode 100644 project/jni/openal/src/Alc/ALu.c create mode 100644 project/jni/openal/src/Alc/alcConfig.c create mode 100644 project/jni/openal/src/Alc/alcEcho.c create mode 100644 project/jni/openal/src/Alc/alcModulator.c create mode 100644 project/jni/openal/src/Alc/alcReverb.c create mode 100644 project/jni/openal/src/Alc/alcRing.c create mode 100644 project/jni/openal/src/Alc/alcThread.c create mode 100644 project/jni/openal/src/Alc/android.c create mode 100644 project/jni/openal/src/Alc/bs2b.c create mode 100644 project/jni/openal/src/Alc/null.c create mode 100644 project/jni/openal/src/OpenAL32/Include/alAuxEffectSlot.h create mode 100644 project/jni/openal/src/OpenAL32/Include/alBuffer.h create mode 100644 project/jni/openal/src/OpenAL32/Include/alDatabuffer.h create mode 100644 project/jni/openal/src/OpenAL32/Include/alEffect.h create mode 100644 project/jni/openal/src/OpenAL32/Include/alError.h create mode 100644 project/jni/openal/src/OpenAL32/Include/alFilter.h create mode 100644 project/jni/openal/src/OpenAL32/Include/alListener.h create mode 100644 project/jni/openal/src/OpenAL32/Include/alMain.h create mode 100644 project/jni/openal/src/OpenAL32/Include/alSource.h create mode 100644 project/jni/openal/src/OpenAL32/Include/alState.h create mode 100644 project/jni/openal/src/OpenAL32/Include/alThunk.h create mode 100644 project/jni/openal/src/OpenAL32/Include/alu.h create mode 100644 project/jni/openal/src/OpenAL32/Include/bs2b.h create mode 100644 project/jni/openal/src/OpenAL32/alAuxEffectSlot.c create mode 100644 project/jni/openal/src/OpenAL32/alBuffer.c create mode 100644 project/jni/openal/src/OpenAL32/alDatabuffer.c create mode 100644 project/jni/openal/src/OpenAL32/alEffect.c create mode 100644 project/jni/openal/src/OpenAL32/alError.c create mode 100644 project/jni/openal/src/OpenAL32/alExtension.c create mode 100644 project/jni/openal/src/OpenAL32/alFilter.c create mode 100644 project/jni/openal/src/OpenAL32/alListener.c create mode 100644 project/jni/openal/src/OpenAL32/alSource.c create mode 100644 project/jni/openal/src/OpenAL32/alState.c create mode 100644 project/jni/openal/src/OpenAL32/alThunk.c create mode 100644 project/jni/openal/src/config.h diff --git a/build.sh b/build.sh index b7a9091f0..ae7558add 100755 --- a/build.sh +++ b/build.sh @@ -15,5 +15,5 @@ if ( grep "package $AppFullName;" project/src/Globals.java > /dev/null && [ "`re touch project/src/Globals.java fi -cd project && env PATH=$NDKBUILDPATH nice -n10 ndk-build -j2 V=1 && ant `test -n "$1" && echo release || echo debug` && cd bin && adb install -r DemoActivity-debug.apk +cd project && env PATH=$NDKBUILDPATH nice -n10 ndk-build -j2 V=1 && ant `test -n "$1" && echo release || echo debug` && test -z "$1" && cd bin && adb install -r DemoActivity-debug.apk diff --git a/project/jni/application/src b/project/jni/application/src index 550b7b622..59d41f41e 120000 --- a/project/jni/application/src +++ b/project/jni/application/src @@ -1 +1 @@ -openttd \ No newline at end of file +fheroes2 \ No newline at end of file diff --git a/project/jni/openal/Android.mk b/project/jni/openal/Android.mk new file mode 100644 index 000000000..d28dd1692 --- /dev/null +++ b/project/jni/openal/Android.mk @@ -0,0 +1,25 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := openal + +APP_SUBDIRS := $(patsubst $(LOCAL_PATH)/%, %, $(shell find $(LOCAL_PATH)/src -type d)) + +LOCAL_CFLAGS := -O3 $(foreach D, $(APP_SUBDIRS), -I$(LOCAL_PATH)/$(D)) \ + -I$(LOCAL_PATH)/include -DHAVE_CONFIG_H -DAL_ALEXT_PROTOTYPES + + + +LOCAL_CPP_EXTENSION := .cpp + +LOCAL_SRC_FILES := $(foreach F, $(APP_SUBDIRS), $(addprefix $(F)/,$(notdir $(wildcard $(LOCAL_PATH)/$(F)/*.cpp)))) +LOCAL_SRC_FILES += $(foreach F, $(APP_SUBDIRS), $(addprefix $(F)/,$(notdir $(wildcard $(LOCAL_PATH)/$(F)/*.c)))) + +LOCAL_SHARED_LIBRARIES := + +LOCAL_STATIC_LIBRARIES := + +LOCAL_LDLIBS := -llog + +include $(BUILD_SHARED_LIBRARY) diff --git a/project/jni/openal/COPYING b/project/jni/openal/COPYING new file mode 100644 index 000000000..d0c897869 --- /dev/null +++ b/project/jni/openal/COPYING @@ -0,0 +1,484 @@ + + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + + Copyright (C) 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. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, 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 library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, 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 companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/project/jni/openal/README b/project/jni/openal/README new file mode 100644 index 000000000..0ff4dc33d --- /dev/null +++ b/project/jni/openal/README @@ -0,0 +1,20 @@ +Source Install +============== + +To install OpenAL Soft, use your favorite shell to go into the build/ +directory, and run: + +cmake .. + +Assuming configuration went well, you can then build it, typically using GNU +Make (KDevelop, MSVC, and others are possible depending on your system setup +and CMake configuration). + +Please Note: Double check that the appropriate backends were detected. Often, +complaints of no sound, crashing, and missing devices can be solved by making +sure the correct backends are being used. CMake's output will identify which +backends were enabled. + +For most systems, you will likely want to make sure ALSA, OSS, and PulseAudio +were detected (if your target system uses them). For Windows, make sure +DirectSound was detected. diff --git a/project/jni/openal/README-ANDROID b/project/jni/openal/README-ANDROID new file mode 100644 index 000000000..9a8c5fcb4 --- /dev/null +++ b/project/jni/openal/README-ANDROID @@ -0,0 +1,51 @@ +OpenAL Soft for Android +======================= + +OpenAL Soft on Android is supported only starting from 1.5 version. + +To build OpenAL Soft for Android you must have install SDK and NDK (at least r4) installed. + +Go to Android directory and execute + +$ PATH/TO/NDK/ndk-build + +This will build libopenal.so and libexample.so under libs subdirectory. +You can use libopenal.so in your own projects. If you want to build Java example, then +first update project to your local SDK installation: + +$ PATH/TO/SDK/tools/android update project --path . --target android-3 + +Run this only once (it will create local.properties file, and update default.properties file). +After that use ant to compile and package Java code: + +$ ant debug + +Now you will find OpenAL-debug.apk under bin directory. Don't worry that it is debug. All the +decoding will be done from native C code from jni/example.c file. +Install it to your device: + +$ adb install -r bin/OpenAL-debug.apk + +And run it either manually, or with am from command-line: + +$ adb shell am start -a android.intent.action.MAIN -n net.strangesoft.kcat/.OpenAL + +Example will decode ogg file using Tremolo library and will play audio with streaming source. +Tremolo library is heavily optimized Tremor library (integer only Vorbis decoder). +It is BSD licensed: http://wss.co.uk/pinknoise/tremolo/ + +You can open DDMS to watch debug logging or any error messages if there is any. You can filter +out OpenAL error/info messages with tag "OpenAL". + +Example is using trash80 song Three/Four Robot Slojam from http://trash80.net/music +It is distributed under Creative Commons license. + +Take into consideration that Android mobile devices is not as powerful as your desktop, so do +not put on OpenAL too many work. Use low sample rate (22050 or better 11025, if not lower) data. +Also create context by specifying lower sample rrate. Take into consideration that not all +Android devices have hardware floting point calculations available. Many of them will execute +floating point calculations in software which is slower. + +-- +Martins Mozeiko +martins.mozeiko@gmail.com diff --git a/project/jni/openal/include/AL/al.h b/project/jni/openal/include/AL/al.h new file mode 100644 index 000000000..c409701f0 --- /dev/null +++ b/project/jni/openal/include/AL/al.h @@ -0,0 +1,722 @@ +#ifndef AL_AL_H +#define AL_AL_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(_WIN32) && !defined(_XBOX) + #if defined(AL_BUILD_LIBRARY) + #define AL_API __declspec(dllexport) + #else + #define AL_API __declspec(dllimport) + #endif +#else + #if defined(AL_BUILD_LIBRARY) && defined(HAVE_GCC_VISIBILITY) + #define AL_API __attribute__((visibility("protected"))) + #else + #define AL_API extern + #endif +#endif + +#if defined(_WIN32) + #define AL_APIENTRY __cdecl +#else + #define AL_APIENTRY +#endif + +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC + #pragma export on +#endif + +/* + * The OPENAL, ALAPI, ALAPIENTRY, AL_INVALID, AL_ILLEGAL_ENUM, and + * AL_ILLEGAL_COMMAND macros are deprecated, but are included for + * applications porting code from AL 1.0 + */ +#define OPENAL +#define ALAPI AL_API +#define ALAPIENTRY AL_APIENTRY +#define AL_INVALID (-1) +#define AL_ILLEGAL_ENUM AL_INVALID_ENUM +#define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION + +#define AL_VERSION_1_0 +#define AL_VERSION_1_1 + + +/** 8-bit boolean */ +typedef char ALboolean; + +/** character */ +typedef char ALchar; + +/** signed 8-bit 2's complement integer */ +typedef signed char ALbyte; + +/** unsigned 8-bit integer */ +typedef unsigned char ALubyte; + +/** signed 16-bit 2's complement integer */ +typedef short ALshort; + +/** unsigned 16-bit integer */ +typedef unsigned short ALushort; + +/** signed 32-bit 2's complement integer */ +typedef int ALint; + +/** unsigned 32-bit integer */ +typedef unsigned int ALuint; + +/** non-negative 32-bit binary integer size */ +typedef int ALsizei; + +/** enumerated 32-bit value */ +typedef int ALenum; + +/** 32-bit IEEE754 floating-point */ +typedef float ALfloat; + +/** 64-bit IEEE754 floating-point */ +typedef double ALdouble; + +/** void type (for opaque pointers only) */ +typedef void ALvoid; + + +/* Enumerant values begin at column 50. No tabs. */ + +/* "no distance model" or "no buffer" */ +#define AL_NONE 0 + +/* Boolean False. */ +#define AL_FALSE 0 + +/** Boolean True. */ +#define AL_TRUE 1 + +/** Indicate Source has relative coordinates. */ +#define AL_SOURCE_RELATIVE 0x202 + + + +/** + * Directional source, inner cone angle, in degrees. + * Range: [0-360] + * Default: 360 + */ +#define AL_CONE_INNER_ANGLE 0x1001 + +/** + * Directional source, outer cone angle, in degrees. + * Range: [0-360] + * Default: 360 + */ +#define AL_CONE_OUTER_ANGLE 0x1002 + +/** + * Specify the pitch to be applied at source. + * Range: [0.5-2.0] + * Default: 1.0 + */ +#define AL_PITCH 0x1003 + +/** + * Specify the current location in three dimensional space. + * OpenAL, like OpenGL, uses a right handed coordinate system, + * where in a frontal default view X (thumb) points right, + * Y points up (index finger), and Z points towards the + * viewer/camera (middle finger). + * To switch from a left handed coordinate system, flip the + * sign on the Z coordinate. + * Listener position is always in the world coordinate system. + */ +#define AL_POSITION 0x1004 + +/** Specify the current direction. */ +#define AL_DIRECTION 0x1005 + +/** Specify the current velocity in three dimensional space. */ +#define AL_VELOCITY 0x1006 + +/** + * Indicate whether source is looping. + * Type: ALboolean? + * Range: [AL_TRUE, AL_FALSE] + * Default: FALSE. + */ +#define AL_LOOPING 0x1007 + +/** + * Indicate the buffer to provide sound samples. + * Type: ALuint. + * Range: any valid Buffer id. + */ +#define AL_BUFFER 0x1009 + +/** + * Indicate the gain (volume amplification) applied. + * Type: ALfloat. + * Range: ]0.0- ] + * A value of 1.0 means un-attenuated/unchanged. + * Each division by 2 equals an attenuation of -6dB. + * Each multiplicaton with 2 equals an amplification of +6dB. + * A value of 0.0 is meaningless with respect to a logarithmic + * scale; it is interpreted as zero volume - the channel + * is effectively disabled. + */ +#define AL_GAIN 0x100A + +/* + * Indicate minimum source attenuation + * Type: ALfloat + * Range: [0.0 - 1.0] + * + * Logarthmic + */ +#define AL_MIN_GAIN 0x100D + +/** + * Indicate maximum source attenuation + * Type: ALfloat + * Range: [0.0 - 1.0] + * + * Logarthmic + */ +#define AL_MAX_GAIN 0x100E + +/** + * Indicate listener orientation. + * + * at/up + */ +#define AL_ORIENTATION 0x100F + +/** + * Source state information. + */ +#define AL_SOURCE_STATE 0x1010 +#define AL_INITIAL 0x1011 +#define AL_PLAYING 0x1012 +#define AL_PAUSED 0x1013 +#define AL_STOPPED 0x1014 + +/** + * Buffer Queue params + */ +#define AL_BUFFERS_QUEUED 0x1015 +#define AL_BUFFERS_PROCESSED 0x1016 + +/** + * Source buffer position information + */ +#define AL_SEC_OFFSET 0x1024 +#define AL_SAMPLE_OFFSET 0x1025 +#define AL_BYTE_OFFSET 0x1026 + +/* + * Source type (Static, Streaming or undetermined) + * Source is Static if a Buffer has been attached using AL_BUFFER + * Source is Streaming if one or more Buffers have been attached using alSourceQueueBuffers + * Source is undetermined when it has the NULL buffer attached + */ +#define AL_SOURCE_TYPE 0x1027 +#define AL_STATIC 0x1028 +#define AL_STREAMING 0x1029 +#define AL_UNDETERMINED 0x1030 + +/** Sound samples: format specifier. */ +#define AL_FORMAT_MONO8 0x1100 +#define AL_FORMAT_MONO16 0x1101 +#define AL_FORMAT_STEREO8 0x1102 +#define AL_FORMAT_STEREO16 0x1103 + +/** + * source specific reference distance + * Type: ALfloat + * Range: 0.0 - +inf + * + * At 0.0, no distance attenuation occurs. Default is + * 1.0. + */ +#define AL_REFERENCE_DISTANCE 0x1020 + +/** + * source specific rolloff factor + * Type: ALfloat + * Range: 0.0 - +inf + * + */ +#define AL_ROLLOFF_FACTOR 0x1021 + +/** + * Directional source, outer cone gain. + * + * Default: 0.0 + * Range: [0.0 - 1.0] + * Logarithmic + */ +#define AL_CONE_OUTER_GAIN 0x1022 + +/** + * Indicate distance above which sources are not + * attenuated using the inverse clamped distance model. + * + * Default: +inf + * Type: ALfloat + * Range: 0.0 - +inf + */ +#define AL_MAX_DISTANCE 0x1023 + +/** + * Sound samples: frequency, in units of Hertz [Hz]. + * This is the number of samples per second. Half of the + * sample frequency marks the maximum significant + * frequency component. + */ +#define AL_FREQUENCY 0x2001 +#define AL_BITS 0x2002 +#define AL_CHANNELS 0x2003 +#define AL_SIZE 0x2004 + +/** + * Buffer state. + * + * Not supported for public use (yet). + */ +#define AL_UNUSED 0x2010 +#define AL_PENDING 0x2011 +#define AL_PROCESSED 0x2012 + + +/** Errors: No Error. */ +#define AL_NO_ERROR AL_FALSE + +/** + * Invalid Name paramater passed to AL call. + */ +#define AL_INVALID_NAME 0xA001 + +/** + * Invalid parameter passed to AL call. + */ +#define AL_INVALID_ENUM 0xA002 + +/** + * Invalid enum parameter value. + */ +#define AL_INVALID_VALUE 0xA003 + +/** + * Illegal call. + */ +#define AL_INVALID_OPERATION 0xA004 + + +/** + * No mojo. + */ +#define AL_OUT_OF_MEMORY 0xA005 + + +/** Context strings: Vendor Name. */ +#define AL_VENDOR 0xB001 +#define AL_VERSION 0xB002 +#define AL_RENDERER 0xB003 +#define AL_EXTENSIONS 0xB004 + +/** Global tweakage. */ + +/** + * Doppler scale. Default 1.0 + */ +#define AL_DOPPLER_FACTOR 0xC000 + +/** + * Tweaks speed of propagation. + */ +#define AL_DOPPLER_VELOCITY 0xC001 + +/** + * Speed of Sound in units per second + */ +#define AL_SPEED_OF_SOUND 0xC003 + +/** + * Distance models + * + * used in conjunction with DistanceModel + * + * implicit: NONE, which disances distance attenuation. + */ +#define AL_DISTANCE_MODEL 0xD000 +#define AL_INVERSE_DISTANCE 0xD001 +#define AL_INVERSE_DISTANCE_CLAMPED 0xD002 +#define AL_LINEAR_DISTANCE 0xD003 +#define AL_LINEAR_DISTANCE_CLAMPED 0xD004 +#define AL_EXPONENT_DISTANCE 0xD005 +#define AL_EXPONENT_DISTANCE_CLAMPED 0xD006 + +/* + * Renderer State management + */ +AL_API void AL_APIENTRY alEnable( ALenum capability ); + +AL_API void AL_APIENTRY alDisable( ALenum capability ); + +AL_API ALboolean AL_APIENTRY alIsEnabled( ALenum capability ); + + +/* + * State retrieval + */ +AL_API const ALchar* AL_APIENTRY alGetString( ALenum param ); + +AL_API void AL_APIENTRY alGetBooleanv( ALenum param, ALboolean* data ); + +AL_API void AL_APIENTRY alGetIntegerv( ALenum param, ALint* data ); + +AL_API void AL_APIENTRY alGetFloatv( ALenum param, ALfloat* data ); + +AL_API void AL_APIENTRY alGetDoublev( ALenum param, ALdouble* data ); + +AL_API ALboolean AL_APIENTRY alGetBoolean( ALenum param ); + +AL_API ALint AL_APIENTRY alGetInteger( ALenum param ); + +AL_API ALfloat AL_APIENTRY alGetFloat( ALenum param ); + +AL_API ALdouble AL_APIENTRY alGetDouble( ALenum param ); + + +/* + * Error support. + * Obtain the most recent error generated in the AL state machine. + */ +AL_API ALenum AL_APIENTRY alGetError( void ); + + +/* + * Extension support. + * Query for the presence of an extension, and obtain any appropriate + * function pointers and enum values. + */ +AL_API ALboolean AL_APIENTRY alIsExtensionPresent( const ALchar* extname ); + +AL_API void* AL_APIENTRY alGetProcAddress( const ALchar* fname ); + +AL_API ALenum AL_APIENTRY alGetEnumValue( const ALchar* ename ); + + +/* + * LISTENER + * Listener represents the location and orientation of the + * 'user' in 3D-space. + * + * Properties include: - + * + * Gain AL_GAIN ALfloat + * Position AL_POSITION ALfloat[3] + * Velocity AL_VELOCITY ALfloat[3] + * Orientation AL_ORIENTATION ALfloat[6] (Forward then Up vectors) +*/ + +/* + * Set Listener parameters + */ +AL_API void AL_APIENTRY alListenerf( ALenum param, ALfloat value ); + +AL_API void AL_APIENTRY alListener3f( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); + +AL_API void AL_APIENTRY alListenerfv( ALenum param, const ALfloat* values ); + +AL_API void AL_APIENTRY alListeneri( ALenum param, ALint value ); + +AL_API void AL_APIENTRY alListener3i( ALenum param, ALint value1, ALint value2, ALint value3 ); + +AL_API void AL_APIENTRY alListeneriv( ALenum param, const ALint* values ); + +/* + * Get Listener parameters + */ +AL_API void AL_APIENTRY alGetListenerf( ALenum param, ALfloat* value ); + +AL_API void AL_APIENTRY alGetListener3f( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 ); + +AL_API void AL_APIENTRY alGetListenerfv( ALenum param, ALfloat* values ); + +AL_API void AL_APIENTRY alGetListeneri( ALenum param, ALint* value ); + +AL_API void AL_APIENTRY alGetListener3i( ALenum param, ALint *value1, ALint *value2, ALint *value3 ); + +AL_API void AL_APIENTRY alGetListeneriv( ALenum param, ALint* values ); + + +/** + * SOURCE + * Sources represent individual sound objects in 3D-space. + * Sources take the PCM data provided in the specified Buffer, + * apply Source-specific modifications, and then + * submit them to be mixed according to spatial arrangement etc. + * + * Properties include: - + * + * Gain AL_GAIN ALfloat + * Min Gain AL_MIN_GAIN ALfloat + * Max Gain AL_MAX_GAIN ALfloat + * Position AL_POSITION ALfloat[3] + * Velocity AL_VELOCITY ALfloat[3] + * Direction AL_DIRECTION ALfloat[3] + * Head Relative Mode AL_SOURCE_RELATIVE ALint (AL_TRUE or AL_FALSE) + * Reference Distance AL_REFERENCE_DISTANCE ALfloat + * Max Distance AL_MAX_DISTANCE ALfloat + * RollOff Factor AL_ROLLOFF_FACTOR ALfloat + * Inner Angle AL_CONE_INNER_ANGLE ALint or ALfloat + * Outer Angle AL_CONE_OUTER_ANGLE ALint or ALfloat + * Cone Outer Gain AL_CONE_OUTER_GAIN ALint or ALfloat + * Pitch AL_PITCH ALfloat + * Looping AL_LOOPING ALint (AL_TRUE or AL_FALSE) + * MS Offset AL_MSEC_OFFSET ALint or ALfloat + * Byte Offset AL_BYTE_OFFSET ALint or ALfloat + * Sample Offset AL_SAMPLE_OFFSET ALint or ALfloat + * Attached Buffer AL_BUFFER ALint + * State (Query only) AL_SOURCE_STATE ALint + * Buffers Queued (Query only) AL_BUFFERS_QUEUED ALint + * Buffers Processed (Query only) AL_BUFFERS_PROCESSED ALint + */ + +/* Create Source objects */ +AL_API void AL_APIENTRY alGenSources( ALsizei n, ALuint* sources ); + +/* Delete Source objects */ +AL_API void AL_APIENTRY alDeleteSources( ALsizei n, const ALuint* sources ); + +/* Verify a handle is a valid Source */ +AL_API ALboolean AL_APIENTRY alIsSource( ALuint sid ); + +/* + * Set Source parameters + */ +AL_API void AL_APIENTRY alSourcef( ALuint sid, ALenum param, ALfloat value ); + +AL_API void AL_APIENTRY alSource3f( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); + +AL_API void AL_APIENTRY alSourcefv( ALuint sid, ALenum param, const ALfloat* values ); + +AL_API void AL_APIENTRY alSourcei( ALuint sid, ALenum param, ALint value ); + +AL_API void AL_APIENTRY alSource3i( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 ); + +AL_API void AL_APIENTRY alSourceiv( ALuint sid, ALenum param, const ALint* values ); + +/* + * Get Source parameters + */ +AL_API void AL_APIENTRY alGetSourcef( ALuint sid, ALenum param, ALfloat* value ); + +AL_API void AL_APIENTRY alGetSource3f( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); + +AL_API void AL_APIENTRY alGetSourcefv( ALuint sid, ALenum param, ALfloat* values ); + +AL_API void AL_APIENTRY alGetSourcei( ALuint sid, ALenum param, ALint* value ); + +AL_API void AL_APIENTRY alGetSource3i( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3); + +AL_API void AL_APIENTRY alGetSourceiv( ALuint sid, ALenum param, ALint* values ); + + +/* + * Source vector based playback calls + */ + +/* Play, replay, or resume (if paused) a list of Sources */ +AL_API void AL_APIENTRY alSourcePlayv( ALsizei ns, const ALuint *sids ); + +/* Stop a list of Sources */ +AL_API void AL_APIENTRY alSourceStopv( ALsizei ns, const ALuint *sids ); + +/* Rewind a list of Sources */ +AL_API void AL_APIENTRY alSourceRewindv( ALsizei ns, const ALuint *sids ); + +/* Pause a list of Sources */ +AL_API void AL_APIENTRY alSourcePausev( ALsizei ns, const ALuint *sids ); + +/* + * Source based playback calls + */ + +/* Play, replay, or resume a Source */ +AL_API void AL_APIENTRY alSourcePlay( ALuint sid ); + +/* Stop a Source */ +AL_API void AL_APIENTRY alSourceStop( ALuint sid ); + +/* Rewind a Source (set playback postiton to beginning) */ +AL_API void AL_APIENTRY alSourceRewind( ALuint sid ); + +/* Pause a Source */ +AL_API void AL_APIENTRY alSourcePause( ALuint sid ); + +/* + * Source Queuing + */ +AL_API void AL_APIENTRY alSourceQueueBuffers( ALuint sid, ALsizei numEntries, const ALuint *bids ); + +AL_API void AL_APIENTRY alSourceUnqueueBuffers( ALuint sid, ALsizei numEntries, ALuint *bids ); + + +/** + * BUFFER + * Buffer objects are storage space for sample data. + * Buffers are referred to by Sources. One Buffer can be used + * by multiple Sources. + * + * Properties include: - + * + * Frequency (Query only) AL_FREQUENCY ALint + * Size (Query only) AL_SIZE ALint + * Bits (Query only) AL_BITS ALint + * Channels (Query only) AL_CHANNELS ALint + */ + +/* Create Buffer objects */ +AL_API void AL_APIENTRY alGenBuffers( ALsizei n, ALuint* buffers ); + +/* Delete Buffer objects */ +AL_API void AL_APIENTRY alDeleteBuffers( ALsizei n, const ALuint* buffers ); + +/* Verify a handle is a valid Buffer */ +AL_API ALboolean AL_APIENTRY alIsBuffer( ALuint bid ); + +/* Specify the data to be copied into a buffer */ +AL_API void AL_APIENTRY alBufferData( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq ); + +/* + * Set Buffer parameters + */ +AL_API void AL_APIENTRY alBufferf( ALuint bid, ALenum param, ALfloat value ); + +AL_API void AL_APIENTRY alBuffer3f( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); + +AL_API void AL_APIENTRY alBufferfv( ALuint bid, ALenum param, const ALfloat* values ); + +AL_API void AL_APIENTRY alBufferi( ALuint bid, ALenum param, ALint value ); + +AL_API void AL_APIENTRY alBuffer3i( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 ); + +AL_API void AL_APIENTRY alBufferiv( ALuint bid, ALenum param, const ALint* values ); + +/* + * Get Buffer parameters + */ +AL_API void AL_APIENTRY alGetBufferf( ALuint bid, ALenum param, ALfloat* value ); + +AL_API void AL_APIENTRY alGetBuffer3f( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); + +AL_API void AL_APIENTRY alGetBufferfv( ALuint bid, ALenum param, ALfloat* values ); + +AL_API void AL_APIENTRY alGetBufferi( ALuint bid, ALenum param, ALint* value ); + +AL_API void AL_APIENTRY alGetBuffer3i( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3); + +AL_API void AL_APIENTRY alGetBufferiv( ALuint bid, ALenum param, ALint* values ); + + +/* + * Global Parameters + */ +AL_API void AL_APIENTRY alDopplerFactor( ALfloat value ); + +AL_API void AL_APIENTRY alDopplerVelocity( ALfloat value ); + +AL_API void AL_APIENTRY alSpeedOfSound( ALfloat value ); + +AL_API void AL_APIENTRY alDistanceModel( ALenum distanceModel ); + +/* + * Pointer-to-function types, useful for dynamically getting AL entry points. + */ +typedef void (AL_APIENTRY *LPALENABLE)( ALenum capability ); +typedef void (AL_APIENTRY *LPALDISABLE)( ALenum capability ); +typedef ALboolean (AL_APIENTRY *LPALISENABLED)( ALenum capability ); +typedef const ALchar* (AL_APIENTRY *LPALGETSTRING)( ALenum param ); +typedef void (AL_APIENTRY *LPALGETBOOLEANV)( ALenum param, ALboolean* data ); +typedef void (AL_APIENTRY *LPALGETINTEGERV)( ALenum param, ALint* data ); +typedef void (AL_APIENTRY *LPALGETFLOATV)( ALenum param, ALfloat* data ); +typedef void (AL_APIENTRY *LPALGETDOUBLEV)( ALenum param, ALdouble* data ); +typedef ALboolean (AL_APIENTRY *LPALGETBOOLEAN)( ALenum param ); +typedef ALint (AL_APIENTRY *LPALGETINTEGER)( ALenum param ); +typedef ALfloat (AL_APIENTRY *LPALGETFLOAT)( ALenum param ); +typedef ALdouble (AL_APIENTRY *LPALGETDOUBLE)( ALenum param ); +typedef ALenum (AL_APIENTRY *LPALGETERROR)( void ); +typedef ALboolean (AL_APIENTRY *LPALISEXTENSIONPRESENT)(const ALchar* extname ); +typedef void* (AL_APIENTRY *LPALGETPROCADDRESS)( const ALchar* fname ); +typedef ALenum (AL_APIENTRY *LPALGETENUMVALUE)( const ALchar* ename ); +typedef void (AL_APIENTRY *LPALLISTENERF)( ALenum param, ALfloat value ); +typedef void (AL_APIENTRY *LPALLISTENER3F)( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); +typedef void (AL_APIENTRY *LPALLISTENERFV)( ALenum param, const ALfloat* values ); +typedef void (AL_APIENTRY *LPALLISTENERI)( ALenum param, ALint value ); +typedef void (AL_APIENTRY *LPALLISTENER3I)( ALenum param, ALint value1, ALint value2, ALint value3 ); +typedef void (AL_APIENTRY *LPALLISTENERIV)( ALenum param, const ALint* values ); +typedef void (AL_APIENTRY *LPALGETLISTENERF)( ALenum param, ALfloat* value ); +typedef void (AL_APIENTRY *LPALGETLISTENER3F)( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 ); +typedef void (AL_APIENTRY *LPALGETLISTENERFV)( ALenum param, ALfloat* values ); +typedef void (AL_APIENTRY *LPALGETLISTENERI)( ALenum param, ALint* value ); +typedef void (AL_APIENTRY *LPALGETLISTENER3I)( ALenum param, ALint *value1, ALint *value2, ALint *value3 ); +typedef void (AL_APIENTRY *LPALGETLISTENERIV)( ALenum param, ALint* values ); +typedef void (AL_APIENTRY *LPALGENSOURCES)( ALsizei n, ALuint* sources ); +typedef void (AL_APIENTRY *LPALDELETESOURCES)( ALsizei n, const ALuint* sources ); +typedef ALboolean (AL_APIENTRY *LPALISSOURCE)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCEF)( ALuint sid, ALenum param, ALfloat value); +typedef void (AL_APIENTRY *LPALSOURCE3F)( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); +typedef void (AL_APIENTRY *LPALSOURCEFV)( ALuint sid, ALenum param, const ALfloat* values ); +typedef void (AL_APIENTRY *LPALSOURCEI)( ALuint sid, ALenum param, ALint value); +typedef void (AL_APIENTRY *LPALSOURCE3I)( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 ); +typedef void (AL_APIENTRY *LPALSOURCEIV)( ALuint sid, ALenum param, const ALint* values ); +typedef void (AL_APIENTRY *LPALGETSOURCEF)( ALuint sid, ALenum param, ALfloat* value ); +typedef void (AL_APIENTRY *LPALGETSOURCE3F)( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); +typedef void (AL_APIENTRY *LPALGETSOURCEFV)( ALuint sid, ALenum param, ALfloat* values ); +typedef void (AL_APIENTRY *LPALGETSOURCEI)( ALuint sid, ALenum param, ALint* value ); +typedef void (AL_APIENTRY *LPALGETSOURCE3I)( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3); +typedef void (AL_APIENTRY *LPALGETSOURCEIV)( ALuint sid, ALenum param, ALint* values ); +typedef void (AL_APIENTRY *LPALSOURCEPLAYV)( ALsizei ns, const ALuint *sids ); +typedef void (AL_APIENTRY *LPALSOURCESTOPV)( ALsizei ns, const ALuint *sids ); +typedef void (AL_APIENTRY *LPALSOURCEREWINDV)( ALsizei ns, const ALuint *sids ); +typedef void (AL_APIENTRY *LPALSOURCEPAUSEV)( ALsizei ns, const ALuint *sids ); +typedef void (AL_APIENTRY *LPALSOURCEPLAY)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCESTOP)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCEREWIND)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCEPAUSE)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint sid, ALsizei numEntries, const ALuint *bids ); +typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint sid, ALsizei numEntries, ALuint *bids ); +typedef void (AL_APIENTRY *LPALGENBUFFERS)( ALsizei n, ALuint* buffers ); +typedef void (AL_APIENTRY *LPALDELETEBUFFERS)( ALsizei n, const ALuint* buffers ); +typedef ALboolean (AL_APIENTRY *LPALISBUFFER)( ALuint bid ); +typedef void (AL_APIENTRY *LPALBUFFERDATA)( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq ); +typedef void (AL_APIENTRY *LPALBUFFERF)( ALuint bid, ALenum param, ALfloat value); +typedef void (AL_APIENTRY *LPALBUFFER3F)( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); +typedef void (AL_APIENTRY *LPALBUFFERFV)( ALuint bid, ALenum param, const ALfloat* values ); +typedef void (AL_APIENTRY *LPALBUFFERI)( ALuint bid, ALenum param, ALint value); +typedef void (AL_APIENTRY *LPALBUFFER3I)( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 ); +typedef void (AL_APIENTRY *LPALBUFFERIV)( ALuint bid, ALenum param, const ALint* values ); +typedef void (AL_APIENTRY *LPALGETBUFFERF)( ALuint bid, ALenum param, ALfloat* value ); +typedef void (AL_APIENTRY *LPALGETBUFFER3F)( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); +typedef void (AL_APIENTRY *LPALGETBUFFERFV)( ALuint bid, ALenum param, ALfloat* values ); +typedef void (AL_APIENTRY *LPALGETBUFFERI)( ALuint bid, ALenum param, ALint* value ); +typedef void (AL_APIENTRY *LPALGETBUFFER3I)( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3); +typedef void (AL_APIENTRY *LPALGETBUFFERIV)( ALuint bid, ALenum param, ALint* values ); +typedef void (AL_APIENTRY *LPALDOPPLERFACTOR)( ALfloat value ); +typedef void (AL_APIENTRY *LPALDOPPLERVELOCITY)( ALfloat value ); +typedef void (AL_APIENTRY *LPALSPEEDOFSOUND)( ALfloat value ); +typedef void (AL_APIENTRY *LPALDISTANCEMODEL)( ALenum distanceModel ); + +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC + #pragma export off +#endif + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +#endif /* AL_AL_H */ diff --git a/project/jni/openal/include/AL/alc.h b/project/jni/openal/include/AL/alc.h new file mode 100644 index 000000000..4e84af422 --- /dev/null +++ b/project/jni/openal/include/AL/alc.h @@ -0,0 +1,275 @@ +#ifndef AL_ALC_H +#define AL_ALC_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(_WIN32) && !defined(_XBOX) + #if defined(AL_BUILD_LIBRARY) + #define ALC_API __declspec(dllexport) + #else + #define ALC_API __declspec(dllimport) + #endif +#else + #if defined(AL_BUILD_LIBRARY) && defined(HAVE_GCC_VISIBILITY) + #define ALC_API __attribute__((visibility("protected"))) + #else + #define ALC_API extern + #endif +#endif + +#if defined(_WIN32) + #define ALC_APIENTRY __cdecl +#else + #define ALC_APIENTRY +#endif + +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC + #pragma export on +#endif + +/* + * The ALCAPI, ALCAPIENTRY, and ALC_INVALID macros are deprecated, but are + * included for applications porting code from AL 1.0 + */ +#define ALCAPI ALC_API +#define ALCAPIENTRY ALC_APIENTRY +#define ALC_INVALID 0 + + +#define ALC_VERSION_0_1 1 + +typedef struct ALCdevice_struct ALCdevice; +typedef struct ALCcontext_struct ALCcontext; + + +/** 8-bit boolean */ +typedef char ALCboolean; + +/** character */ +typedef char ALCchar; + +/** signed 8-bit 2's complement integer */ +typedef signed char ALCbyte; + +/** unsigned 8-bit integer */ +typedef unsigned char ALCubyte; + +/** signed 16-bit 2's complement integer */ +typedef short ALCshort; + +/** unsigned 16-bit integer */ +typedef unsigned short ALCushort; + +/** signed 32-bit 2's complement integer */ +typedef int ALCint; + +/** unsigned 32-bit integer */ +typedef unsigned int ALCuint; + +/** non-negative 32-bit binary integer size */ +typedef int ALCsizei; + +/** enumerated 32-bit value */ +typedef int ALCenum; + +/** 32-bit IEEE754 floating-point */ +typedef float ALCfloat; + +/** 64-bit IEEE754 floating-point */ +typedef double ALCdouble; + +/** void type (for opaque pointers only) */ +typedef void ALCvoid; + + +/* Enumerant values begin at column 50. No tabs. */ + +/* Boolean False. */ +#define ALC_FALSE 0 + +/* Boolean True. */ +#define ALC_TRUE 1 + +/** + * followed by Hz + */ +#define ALC_FREQUENCY 0x1007 + +/** + * followed by Hz + */ +#define ALC_REFRESH 0x1008 + +/** + * followed by AL_TRUE, AL_FALSE + */ +#define ALC_SYNC 0x1009 + +/** + * followed by Num of requested Mono (3D) Sources + */ +#define ALC_MONO_SOURCES 0x1010 + +/** + * followed by Num of requested Stereo Sources + */ +#define ALC_STEREO_SOURCES 0x1011 + +/** + * errors + */ + +/** + * No error + */ +#define ALC_NO_ERROR ALC_FALSE + +/** + * No device + */ +#define ALC_INVALID_DEVICE 0xA001 + +/** + * invalid context ID + */ +#define ALC_INVALID_CONTEXT 0xA002 + +/** + * bad enum + */ +#define ALC_INVALID_ENUM 0xA003 + +/** + * bad value + */ +#define ALC_INVALID_VALUE 0xA004 + +/** + * Out of memory. + */ +#define ALC_OUT_OF_MEMORY 0xA005 + + +/** + * The Specifier string for default device + */ +#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 +#define ALC_DEVICE_SPECIFIER 0x1005 +#define ALC_EXTENSIONS 0x1006 + +#define ALC_MAJOR_VERSION 0x1000 +#define ALC_MINOR_VERSION 0x1001 + +#define ALC_ATTRIBUTES_SIZE 0x1002 +#define ALC_ALL_ATTRIBUTES 0x1003 + + +/** + * Capture extension + */ +#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310 +#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311 +#define ALC_CAPTURE_SAMPLES 0x312 + + +/* + * Context Management + */ +ALC_API ALCcontext * ALC_APIENTRY alcCreateContext( ALCdevice *device, const ALCint* attrlist ); + +ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent( ALCcontext *context ); + +ALC_API void ALC_APIENTRY alcProcessContext( ALCcontext *context ); + +ALC_API void ALC_APIENTRY alcSuspendContext( ALCcontext *context ); + +ALC_API void ALC_APIENTRY alcDestroyContext( ALCcontext *context ); + +ALC_API ALCcontext * ALC_APIENTRY alcGetCurrentContext( void ); + +ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice( ALCcontext *context ); + + +/* + * Device Management + */ +ALC_API ALCdevice * ALC_APIENTRY alcOpenDevice( const ALCchar *devicename ); + +ALC_API ALCboolean ALC_APIENTRY alcCloseDevice( ALCdevice *device ); + + +/* + * Error support. + * Obtain the most recent Context error + */ +ALC_API ALCenum ALC_APIENTRY alcGetError( ALCdevice *device ); + + +/* + * Extension support. + * Query for the presence of an extension, and obtain any appropriate + * function pointers and enum values. + */ +ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent( ALCdevice *device, const ALCchar *extname ); + +ALC_API void * ALC_APIENTRY alcGetProcAddress( ALCdevice *device, const ALCchar *funcname ); + +ALC_API ALCenum ALC_APIENTRY alcGetEnumValue( ALCdevice *device, const ALCchar *enumname ); + + +/* + * Query functions + */ +ALC_API const ALCchar * ALC_APIENTRY alcGetString( ALCdevice *device, ALCenum param ); + +ALC_API void ALC_APIENTRY alcGetIntegerv( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *data ); + + +/* + * Capture functions + */ +ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize ); + +ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice( ALCdevice *device ); + +ALC_API void ALC_APIENTRY alcCaptureStart( ALCdevice *device ); + +ALC_API void ALC_APIENTRY alcCaptureStop( ALCdevice *device ); + +ALC_API void ALC_APIENTRY alcCaptureSamples( ALCdevice *device, ALCvoid *buffer, ALCsizei samples ); + +/* + * Pointer-to-function types, useful for dynamically getting ALC entry points. + */ +typedef ALCcontext * (ALC_APIENTRY *LPALCCREATECONTEXT) (ALCdevice *device, const ALCint *attrlist); +typedef ALCboolean (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)( ALCcontext *context ); +typedef void (ALC_APIENTRY *LPALCPROCESSCONTEXT)( ALCcontext *context ); +typedef void (ALC_APIENTRY *LPALCSUSPENDCONTEXT)( ALCcontext *context ); +typedef void (ALC_APIENTRY *LPALCDESTROYCONTEXT)( ALCcontext *context ); +typedef ALCcontext * (ALC_APIENTRY *LPALCGETCURRENTCONTEXT)( void ); +typedef ALCdevice * (ALC_APIENTRY *LPALCGETCONTEXTSDEVICE)( ALCcontext *context ); +typedef ALCdevice * (ALC_APIENTRY *LPALCOPENDEVICE)( const ALCchar *devicename ); +typedef ALCboolean (ALC_APIENTRY *LPALCCLOSEDEVICE)( ALCdevice *device ); +typedef ALCenum (ALC_APIENTRY *LPALCGETERROR)( ALCdevice *device ); +typedef ALCboolean (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)( ALCdevice *device, const ALCchar *extname ); +typedef void * (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname ); +typedef ALCenum (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname ); +typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)( ALCdevice *device, ALCenum param ); +typedef void (ALC_APIENTRY *LPALCGETINTEGERV)( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *dest ); +typedef ALCdevice * (ALC_APIENTRY *LPALCCAPTUREOPENDEVICE)( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize ); +typedef ALCboolean (ALC_APIENTRY *LPALCCAPTURECLOSEDEVICE)( ALCdevice *device ); +typedef void (ALC_APIENTRY *LPALCCAPTURESTART)( ALCdevice *device ); +typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)( ALCdevice *device ); +typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)( ALCdevice *device, ALCvoid *buffer, ALCsizei samples ); + +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC + #pragma export off +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* AL_ALC_H */ diff --git a/project/jni/openal/include/AL/alext.h b/project/jni/openal/include/AL/alext.h new file mode 100644 index 000000000..eadc715d8 --- /dev/null +++ b/project/jni/openal/include/AL/alext.h @@ -0,0 +1,150 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2008 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#ifndef AL_ALEXT_H +#define AL_ALEXT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef AL_LOKI_IMA_ADPCM_format +#define AL_LOKI_IMA_ADPCM_format 1 +#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000 +#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001 +#endif + +#ifndef AL_LOKI_WAVE_format +#define AL_LOKI_WAVE_format 1 +#define AL_FORMAT_WAVE_EXT 0x10002 +#endif + +#ifndef AL_EXT_vorbis +#define AL_EXT_vorbis 1 +#define AL_FORMAT_VORBIS_EXT 0x10003 +#endif + +#ifndef AL_LOKI_quadriphonic +#define AL_LOKI_quadriphonic 1 +#define AL_FORMAT_QUAD8_LOKI 0x10004 +#define AL_FORMAT_QUAD16_LOKI 0x10005 +#endif + +#ifndef AL_EXT_float32 +#define AL_EXT_float32 1 +#define AL_FORMAT_MONO_FLOAT32 0x10010 +#define AL_FORMAT_STEREO_FLOAT32 0x10011 +#endif + +#ifndef AL_EXT_double +#define AL_EXT_double 1 +#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012 +#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013 +#endif + +#ifndef ALC_LOKI_audio_channel +#define ALC_LOKI_audio_channel 1 +#define ALC_CHAN_MAIN_LOKI 0x500001 +#define ALC_CHAN_PCM_LOKI 0x500002 +#define ALC_CHAN_CD_LOKI 0x500003 +#endif + +#ifndef ALC_ENUMERATE_ALL_EXT +#define ALC_ENUMERATE_ALL_EXT 1 +#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012 +#define ALC_ALL_DEVICES_SPECIFIER 0x1013 +#endif + +#ifndef AL_EXT_MCFORMATS +#define AL_EXT_MCFORMATS 1 +#define AL_FORMAT_QUAD8 0x1204 +#define AL_FORMAT_QUAD16 0x1205 +#define AL_FORMAT_QUAD32 0x1206 +#define AL_FORMAT_REAR8 0x1207 +#define AL_FORMAT_REAR16 0x1208 +#define AL_FORMAT_REAR32 0x1209 +#define AL_FORMAT_51CHN8 0x120A +#define AL_FORMAT_51CHN16 0x120B +#define AL_FORMAT_51CHN32 0x120C +#define AL_FORMAT_61CHN8 0x120D +#define AL_FORMAT_61CHN16 0x120E +#define AL_FORMAT_61CHN32 0x120F +#define AL_FORMAT_71CHN8 0x1210 +#define AL_FORMAT_71CHN16 0x1211 +#define AL_FORMAT_71CHN32 0x1212 +#endif + +#ifndef AL_EXT_MULAW_MCFORMATS +#define AL_EXT_MULAW_MCFORMATS 1 +#define AL_FORMAT_MONO_MULAW 0x10014 +#define AL_FORMAT_STEREO_MULAW 0x10015 +#define AL_FORMAT_QUAD_MULAW 0x10021 +#define AL_FORMAT_REAR_MULAW 0x10022 +#define AL_FORMAT_51CHN_MULAW 0x10023 +#define AL_FORMAT_61CHN_MULAW 0x10024 +#define AL_FORMAT_71CHN_MULAW 0x10025 +#endif + +#ifndef AL_EXT_IMA4 +#define AL_EXT_IMA4 1 +#define AL_FORMAT_MONO_IMA4 0x1300 +#define AL_FORMAT_STEREO_IMA4 0x1301 +#endif + +#ifndef AL_EXT_STATIC_BUFFER +#define AL_EXT_STATIC_BUFFER 1 +typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq); +#endif +#endif + +#ifndef ALC_EXT_EFX +#define ALC_EXT_EFX 1 +#include "efx.h" +#endif + +#ifndef ALC_EXT_disconnect +#define ALC_EXT_disconnect 1 +#define ALC_CONNECTED 0x313 +#endif + +#ifndef ALC_EXT_thread_local_context +#define ALC_EXT_thread_local_context 1 +typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context); +typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context); +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void); +#endif +#endif + +#ifndef AL_EXT_source_distance_model +#define AL_EXT_source_distance_model 1 +#define AL_SOURCE_DISTANCE_MODEL 0x200 +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/jni/openal/include/AL/efx-creative.h b/project/jni/openal/include/AL/efx-creative.h new file mode 100644 index 000000000..0a04c982e --- /dev/null +++ b/project/jni/openal/include/AL/efx-creative.h @@ -0,0 +1,3 @@ +/* The tokens that would be defined here are already defined in efx.h. This + * empty file is here to provide compatibility with Windows-based projects + * that would include it. */ diff --git a/project/jni/openal/include/AL/efx.h b/project/jni/openal/include/AL/efx.h new file mode 100644 index 000000000..0ccef95d6 --- /dev/null +++ b/project/jni/openal/include/AL/efx.h @@ -0,0 +1,758 @@ +#ifndef AL_EFX_H +#define AL_EFX_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#define ALC_EXT_EFX_NAME "ALC_EXT_EFX" + +#define ALC_EFX_MAJOR_VERSION 0x20001 +#define ALC_EFX_MINOR_VERSION 0x20002 +#define ALC_MAX_AUXILIARY_SENDS 0x20003 + + +/* Listener properties. */ +#define AL_METERS_PER_UNIT 0x20004 + +/* Source properties. */ +#define AL_DIRECT_FILTER 0x20005 +#define AL_AUXILIARY_SEND_FILTER 0x20006 +#define AL_AIR_ABSORPTION_FACTOR 0x20007 +#define AL_ROOM_ROLLOFF_FACTOR 0x20008 +#define AL_CONE_OUTER_GAINHF 0x20009 +#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000A +#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B +#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C + + +/* Effect properties. */ + +/* Reverb effect parameters */ +#define AL_REVERB_DENSITY 0x0001 +#define AL_REVERB_DIFFUSION 0x0002 +#define AL_REVERB_GAIN 0x0003 +#define AL_REVERB_GAINHF 0x0004 +#define AL_REVERB_DECAY_TIME 0x0005 +#define AL_REVERB_DECAY_HFRATIO 0x0006 +#define AL_REVERB_REFLECTIONS_GAIN 0x0007 +#define AL_REVERB_REFLECTIONS_DELAY 0x0008 +#define AL_REVERB_LATE_REVERB_GAIN 0x0009 +#define AL_REVERB_LATE_REVERB_DELAY 0x000A +#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B +#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C +#define AL_REVERB_DECAY_HFLIMIT 0x000D + +/* EAX Reverb effect parameters */ +#define AL_EAXREVERB_DENSITY 0x0001 +#define AL_EAXREVERB_DIFFUSION 0x0002 +#define AL_EAXREVERB_GAIN 0x0003 +#define AL_EAXREVERB_GAINHF 0x0004 +#define AL_EAXREVERB_GAINLF 0x0005 +#define AL_EAXREVERB_DECAY_TIME 0x0006 +#define AL_EAXREVERB_DECAY_HFRATIO 0x0007 +#define AL_EAXREVERB_DECAY_LFRATIO 0x0008 +#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009 +#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A +#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B +#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C +#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D +#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E +#define AL_EAXREVERB_ECHO_TIME 0x000F +#define AL_EAXREVERB_ECHO_DEPTH 0x0010 +#define AL_EAXREVERB_MODULATION_TIME 0x0011 +#define AL_EAXREVERB_MODULATION_DEPTH 0x0012 +#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013 +#define AL_EAXREVERB_HFREFERENCE 0x0014 +#define AL_EAXREVERB_LFREFERENCE 0x0015 +#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016 +#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017 + +/* Chorus effect parameters */ +#define AL_CHORUS_WAVEFORM 0x0001 +#define AL_CHORUS_PHASE 0x0002 +#define AL_CHORUS_RATE 0x0003 +#define AL_CHORUS_DEPTH 0x0004 +#define AL_CHORUS_FEEDBACK 0x0005 +#define AL_CHORUS_DELAY 0x0006 + +/* Distortion effect parameters */ +#define AL_DISTORTION_EDGE 0x0001 +#define AL_DISTORTION_GAIN 0x0002 +#define AL_DISTORTION_LOWPASS_CUTOFF 0x0003 +#define AL_DISTORTION_EQCENTER 0x0004 +#define AL_DISTORTION_EQBANDWIDTH 0x0005 + +/* Echo effect parameters */ +#define AL_ECHO_DELAY 0x0001 +#define AL_ECHO_LRDELAY 0x0002 +#define AL_ECHO_DAMPING 0x0003 +#define AL_ECHO_FEEDBACK 0x0004 +#define AL_ECHO_SPREAD 0x0005 + +/* Flanger effect parameters */ +#define AL_FLANGER_WAVEFORM 0x0001 +#define AL_FLANGER_PHASE 0x0002 +#define AL_FLANGER_RATE 0x0003 +#define AL_FLANGER_DEPTH 0x0004 +#define AL_FLANGER_FEEDBACK 0x0005 +#define AL_FLANGER_DELAY 0x0006 + +/* Frequency shifter effect parameters */ +#define AL_FREQUENCY_SHIFTER_FREQUENCY 0x0001 +#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION 0x0002 +#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION 0x0003 + +/* Vocal morpher effect parameters */ +#define AL_VOCAL_MORPHER_PHONEMEA 0x0001 +#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING 0x0002 +#define AL_VOCAL_MORPHER_PHONEMEB 0x0003 +#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING 0x0004 +#define AL_VOCAL_MORPHER_WAVEFORM 0x0005 +#define AL_VOCAL_MORPHER_RATE 0x0006 + +/* Pitchshifter effect parameters */ +#define AL_PITCH_SHIFTER_COARSE_TUNE 0x0001 +#define AL_PITCH_SHIFTER_FINE_TUNE 0x0002 + +/* Ringmodulator effect parameters */ +#define AL_RING_MODULATOR_FREQUENCY 0x0001 +#define AL_RING_MODULATOR_HIGHPASS_CUTOFF 0x0002 +#define AL_RING_MODULATOR_WAVEFORM 0x0003 + +/* Autowah effect parameters */ +#define AL_AUTOWAH_ATTACK_TIME 0x0001 +#define AL_AUTOWAH_RELEASE_TIME 0x0002 +#define AL_AUTOWAH_RESONANCE 0x0003 +#define AL_AUTOWAH_PEAK_GAIN 0x0004 + +/* Compressor effect parameters */ +#define AL_COMPRESSOR_ONOFF 0x0001 + +/* Equalizer effect parameters */ +#define AL_EQUALIZER_LOW_GAIN 0x0001 +#define AL_EQUALIZER_LOW_CUTOFF 0x0002 +#define AL_EQUALIZER_MID1_GAIN 0x0003 +#define AL_EQUALIZER_MID1_CENTER 0x0004 +#define AL_EQUALIZER_MID1_WIDTH 0x0005 +#define AL_EQUALIZER_MID2_GAIN 0x0006 +#define AL_EQUALIZER_MID2_CENTER 0x0007 +#define AL_EQUALIZER_MID2_WIDTH 0x0008 +#define AL_EQUALIZER_HIGH_GAIN 0x0009 +#define AL_EQUALIZER_HIGH_CUTOFF 0x000A + +/* Effect type */ +#define AL_EFFECT_FIRST_PARAMETER 0x0000 +#define AL_EFFECT_LAST_PARAMETER 0x8000 +#define AL_EFFECT_TYPE 0x8001 + +/* Effect types, used with the AL_EFFECT_TYPE property */ +#define AL_EFFECT_NULL 0x0000 +#define AL_EFFECT_REVERB 0x0001 +#define AL_EFFECT_CHORUS 0x0002 +#define AL_EFFECT_DISTORTION 0x0003 +#define AL_EFFECT_ECHO 0x0004 +#define AL_EFFECT_FLANGER 0x0005 +#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006 +#define AL_EFFECT_VOCAL_MORPHER 0x0007 +#define AL_EFFECT_PITCH_SHIFTER 0x0008 +#define AL_EFFECT_RING_MODULATOR 0x0009 +#define AL_EFFECT_AUTOWAH 0x000A +#define AL_EFFECT_COMPRESSOR 0x000B +#define AL_EFFECT_EQUALIZER 0x000C +#define AL_EFFECT_EAXREVERB 0x8000 + +/* Auxiliary Effect Slot properties. */ +#define AL_EFFECTSLOT_EFFECT 0x0001 +#define AL_EFFECTSLOT_GAIN 0x0002 +#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003 + +/* NULL Auxiliary Slot ID to disable a source send. */ +#define AL_EFFECTSLOT_NULL 0x0000 + + +/* Filter properties. */ + +/* Lowpass filter parameters */ +#define AL_LOWPASS_GAIN 0x0001 +#define AL_LOWPASS_GAINHF 0x0002 + +/* Highpass filter parameters */ +#define AL_HIGHPASS_GAIN 0x0001 +#define AL_HIGHPASS_GAINLF 0x0002 + +/* Bandpass filter parameters */ +#define AL_BANDPASS_GAIN 0x0001 +#define AL_BANDPASS_GAINLF 0x0002 +#define AL_BANDPASS_GAINHF 0x0003 + +/* Filter type */ +#define AL_FILTER_FIRST_PARAMETER 0x0000 +#define AL_FILTER_LAST_PARAMETER 0x8000 +#define AL_FILTER_TYPE 0x8001 + +/* Filter types, used with the AL_FILTER_TYPE property */ +#define AL_FILTER_NULL 0x0000 +#define AL_FILTER_LOWPASS 0x0001 +#define AL_FILTER_HIGHPASS 0x0002 +#define AL_FILTER_BANDPASS 0x0003 + + +/* Effect object function types. */ +typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint); +typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*); + +/* Filter object function types. */ +typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint); +typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*); + +/* Auxiliary Effect Slot object function types. */ +typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*); + +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects); +AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects); +AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect); +AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues); + +AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters); +AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters); +AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter); +AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues); + +AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots); +AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots); +AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues); +#endif + +/* Filter ranges and defaults. */ + +/* Lowpass filter */ +#define LOWPASS_MIN_GAIN (0.0f) +#define LOWPASS_MAX_GAIN (1.0f) +#define LOWPASS_DEFAULT_GAIN (1.0f) + +#define LOWPASS_MIN_GAINHF (0.0f) +#define LOWPASS_MAX_GAINHF (1.0f) +#define LOWPASS_DEFAULT_GAINHF (1.0f) + +/* Highpass filter */ +#define HIGHPASS_MIN_GAIN (0.0f) +#define HIGHPASS_MAX_GAIN (1.0f) +#define HIGHPASS_DEFAULT_GAIN (1.0f) + +#define HIGHPASS_MIN_GAINLF (0.0f) +#define HIGHPASS_MAX_GAINLF (1.0f) +#define HIGHPASS_DEFAULT_GAINLF (1.0f) + +/* Bandpass filter */ +#define BANDPASS_MIN_GAIN (0.0f) +#define BANDPASS_MAX_GAIN (1.0f) +#define BANDPASS_DEFAULT_GAIN (1.0f) + +#define BANDPASS_MIN_GAINHF (0.0f) +#define BANDPASS_MAX_GAINHF (1.0f) +#define BANDPASS_DEFAULT_GAINHF (1.0f) + +#define BANDPASS_MIN_GAINLF (0.0f) +#define BANDPASS_MAX_GAINLF (1.0f) +#define BANDPASS_DEFAULT_GAINLF (1.0f) + + +/* Effect parameter ranges and defaults. */ + +/* Standard reverb effect */ +#define AL_REVERB_MIN_DENSITY (0.0f) +#define AL_REVERB_MAX_DENSITY (1.0f) +#define AL_REVERB_DEFAULT_DENSITY (1.0f) + +#define AL_REVERB_MIN_DIFFUSION (0.0f) +#define AL_REVERB_MAX_DIFFUSION (1.0f) +#define AL_REVERB_DEFAULT_DIFFUSION (1.0f) + +#define AL_REVERB_MIN_GAIN (0.0f) +#define AL_REVERB_MAX_GAIN (1.0f) +#define AL_REVERB_DEFAULT_GAIN (0.32f) + +#define AL_REVERB_MIN_GAINHF (0.0f) +#define AL_REVERB_MAX_GAINHF (1.0f) +#define AL_REVERB_DEFAULT_GAINHF (0.89f) + +#define AL_REVERB_MIN_DECAY_TIME (0.1f) +#define AL_REVERB_MAX_DECAY_TIME (20.0f) +#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f) + +#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f) +#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f) +#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f) + +#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f) +#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f) +#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) + +#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f) +#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f) +#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) + +#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f) +#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f) +#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) + +#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f) +#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f) +#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) + +#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) +#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) +#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) + +#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_REVERB_MIN_DECAY_HFLIMIT AL_FALSE +#define AL_REVERB_MAX_DECAY_HFLIMIT AL_TRUE +#define AL_REVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE + +/* EAX reverb effect */ +#define AL_EAXREVERB_MIN_DENSITY (0.0f) +#define AL_EAXREVERB_MAX_DENSITY (1.0f) +#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f) + +#define AL_EAXREVERB_MIN_DIFFUSION (0.0f) +#define AL_EAXREVERB_MAX_DIFFUSION (1.0f) +#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f) + +#define AL_EAXREVERB_MIN_GAIN (0.0f) +#define AL_EAXREVERB_MAX_GAIN (1.0f) +#define AL_EAXREVERB_DEFAULT_GAIN (0.32f) + +#define AL_EAXREVERB_MIN_GAINHF (0.0f) +#define AL_EAXREVERB_MAX_GAINHF (1.0f) +#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f) + +#define AL_EAXREVERB_MIN_GAINLF (0.0f) +#define AL_EAXREVERB_MAX_GAINLF (1.0f) +#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f) + +#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f) +#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f) + +#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f) +#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f) + +#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f) +#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f) + +#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f) +#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f) +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) + +#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f) +#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f) +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) + +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f) + +#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f) +#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f) +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) + +#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f) +#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f) +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) + +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f) + +#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f) +#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f) +#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f) + +#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f) +#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f) +#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f) + +#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f) +#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f) +#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f) + +#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f) +#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f) +#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f) + +#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) +#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) +#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) + +#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f) +#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f) +#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f) + +#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f) +#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f) +#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f) + +#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_EAXREVERB_MIN_DECAY_HFLIMIT AL_FALSE +#define AL_EAXREVERB_MAX_DECAY_HFLIMIT AL_TRUE +#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE + +/* Chorus effect */ +#define AL_CHORUS_WAVEFORM_SINUSOID (0) +#define AL_CHORUS_WAVEFORM_TRIANGLE (1) + +#define AL_CHORUS_MIN_WAVEFORM (0) +#define AL_CHORUS_MAX_WAVEFORM (1) +#define AL_CHORUS_DEFAULT_WAVEFORM (1) + +#define AL_CHORUS_MIN_PHASE (-180) +#define AL_CHORUS_MAX_PHASE (180) +#define AL_CHORUS_DEFAULT_PHASE (90) + +#define AL_CHORUS_MIN_RATE (0.0f) +#define AL_CHORUS_MAX_RATE (10.0f) +#define AL_CHORUS_DEFAULT_RATE (1.1f) + +#define AL_CHORUS_MIN_DEPTH (0.0f) +#define AL_CHORUS_MAX_DEPTH (1.0f) +#define AL_CHORUS_DEFAULT_DEPTH (0.1f) + +#define AL_CHORUS_MIN_FEEDBACK (-1.0f) +#define AL_CHORUS_MAX_FEEDBACK (1.0f) +#define AL_CHORUS_DEFAULT_FEEDBACK (0.25f) + +#define AL_CHORUS_MIN_DELAY (0.0f) +#define AL_CHORUS_MAX_DELAY (0.016f) +#define AL_CHORUS_DEFAULT_DELAY (0.016f) + +/* Distortion effect */ +#define AL_DISTORTION_MIN_EDGE (0.0f) +#define AL_DISTORTION_MAX_EDGE (1.0f) +#define AL_DISTORTION_DEFAULT_EDGE (0.2f) + +#define AL_DISTORTION_MIN_GAIN (0.01f) +#define AL_DISTORTION_MAX_GAIN (1.0f) +#define AL_DISTORTION_DEFAULT_GAIN (0.05f) + +#define AL_DISTORTION_MIN_LOWPASS_CUTOFF (80.0f) +#define AL_DISTORTION_MAX_LOWPASS_CUTOFF (24000.0f) +#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF (8000.0f) + +#define AL_DISTORTION_MIN_EQCENTER (80.0f) +#define AL_DISTORTION_MAX_EQCENTER (24000.0f) +#define AL_DISTORTION_DEFAULT_EQCENTER (3600.0f) + +#define AL_DISTORTION_MIN_EQBANDWIDTH (80.0f) +#define AL_DISTORTION_MAX_EQBANDWIDTH (24000.0f) +#define AL_DISTORTION_DEFAULT_EQBANDWIDTH (3600.0f) + +/* Echo effect */ +#define AL_ECHO_MIN_DELAY (0.0f) +#define AL_ECHO_MAX_DELAY (0.207f) +#define AL_ECHO_DEFAULT_DELAY (0.1f) + +#define AL_ECHO_MIN_LRDELAY (0.0f) +#define AL_ECHO_MAX_LRDELAY (0.404f) +#define AL_ECHO_DEFAULT_LRDELAY (0.1f) + +#define AL_ECHO_MIN_DAMPING (0.0f) +#define AL_ECHO_MAX_DAMPING (0.99f) +#define AL_ECHO_DEFAULT_DAMPING (0.5f) + +#define AL_ECHO_MIN_FEEDBACK (0.0f) +#define AL_ECHO_MAX_FEEDBACK (1.0f) +#define AL_ECHO_DEFAULT_FEEDBACK (0.5f) + +#define AL_ECHO_MIN_SPREAD (-1.0f) +#define AL_ECHO_MAX_SPREAD (1.0f) +#define AL_ECHO_DEFAULT_SPREAD (-1.0f) + +/* Flanger effect */ +#define AL_FLANGER_WAVEFORM_SINUSOID (0) +#define AL_FLANGER_WAVEFORM_TRIANGLE (1) + +#define AL_FLANGER_MIN_WAVEFORM (0) +#define AL_FLANGER_MAX_WAVEFORM (1) +#define AL_FLANGER_DEFAULT_WAVEFORM (1) + +#define AL_FLANGER_MIN_PHASE (-180) +#define AL_FLANGER_MAX_PHASE (180) +#define AL_FLANGER_DEFAULT_PHASE (0) + +#define AL_FLANGER_MIN_RATE (0.0f) +#define AL_FLANGER_MAX_RATE (10.0f) +#define AL_FLANGER_DEFAULT_RATE (0.27f) + +#define AL_FLANGER_MIN_DEPTH (0.0f) +#define AL_FLANGER_MAX_DEPTH (1.0f) +#define AL_FLANGER_DEFAULT_DEPTH (1.0f) + +#define AL_FLANGER_MIN_FEEDBACK (-1.0f) +#define AL_FLANGER_MAX_FEEDBACK (1.0f) +#define AL_FLANGER_DEFAULT_FEEDBACK (-0.5f) + +#define AL_FLANGER_MIN_DELAY (0.0f) +#define AL_FLANGER_MAX_DELAY (0.004f) +#define AL_FLANGER_DEFAULT_DELAY (0.002f) + +/* Frequency shifter effect */ +#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY (0.0f) +#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY (24000.0f) +#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY (0.0f) + +#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION (0) +#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION (2) +#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0) + +#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN (0) +#define AL_FREQUENCY_SHIFTER_DIRECTION_UP (1) +#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF (2) + +#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0) +#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2) +#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0) + +/* Vocal morpher effect */ +#define AL_VOCAL_MORPHER_MIN_PHONEMEA (0) +#define AL_VOCAL_MORPHER_MAX_PHONEMEA (29) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA (0) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24) +#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEB (0) +#define AL_VOCAL_MORPHER_MAX_PHONEMEB (29) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB (10) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24) +#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0) + +#define AL_VOCAL_MORPHER_PHONEME_A (0) +#define AL_VOCAL_MORPHER_PHONEME_E (1) +#define AL_VOCAL_MORPHER_PHONEME_I (2) +#define AL_VOCAL_MORPHER_PHONEME_O (3) +#define AL_VOCAL_MORPHER_PHONEME_U (4) +#define AL_VOCAL_MORPHER_PHONEME_AA (5) +#define AL_VOCAL_MORPHER_PHONEME_AE (6) +#define AL_VOCAL_MORPHER_PHONEME_AH (7) +#define AL_VOCAL_MORPHER_PHONEME_AO (8) +#define AL_VOCAL_MORPHER_PHONEME_EH (9) +#define AL_VOCAL_MORPHER_PHONEME_ER (10) +#define AL_VOCAL_MORPHER_PHONEME_IH (11) +#define AL_VOCAL_MORPHER_PHONEME_IY (12) +#define AL_VOCAL_MORPHER_PHONEME_UH (13) +#define AL_VOCAL_MORPHER_PHONEME_UW (14) +#define AL_VOCAL_MORPHER_PHONEME_B (15) +#define AL_VOCAL_MORPHER_PHONEME_D (16) +#define AL_VOCAL_MORPHER_PHONEME_F (17) +#define AL_VOCAL_MORPHER_PHONEME_G (18) +#define AL_VOCAL_MORPHER_PHONEME_J (19) +#define AL_VOCAL_MORPHER_PHONEME_K (20) +#define AL_VOCAL_MORPHER_PHONEME_L (21) +#define AL_VOCAL_MORPHER_PHONEME_M (22) +#define AL_VOCAL_MORPHER_PHONEME_N (23) +#define AL_VOCAL_MORPHER_PHONEME_P (24) +#define AL_VOCAL_MORPHER_PHONEME_R (25) +#define AL_VOCAL_MORPHER_PHONEME_S (26) +#define AL_VOCAL_MORPHER_PHONEME_T (27) +#define AL_VOCAL_MORPHER_PHONEME_V (28) +#define AL_VOCAL_MORPHER_PHONEME_Z (29) + +#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID (0) +#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE (1) +#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH (2) + +#define AL_VOCAL_MORPHER_MIN_WAVEFORM (0) +#define AL_VOCAL_MORPHER_MAX_WAVEFORM (2) +#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM (0) + +#define AL_VOCAL_MORPHER_MIN_RATE (0.0f) +#define AL_VOCAL_MORPHER_MAX_RATE (10.0f) +#define AL_VOCAL_MORPHER_DEFAULT_RATE (1.41f) + +/* Pitch shifter effect */ +#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE (-12) +#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE (12) +#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE (12) + +#define AL_PITCH_SHIFTER_MIN_FINE_TUNE (-50) +#define AL_PITCH_SHIFTER_MAX_FINE_TUNE (50) +#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE (0) + +/* Ring modulator effect */ +#define AL_RING_MODULATOR_MIN_FREQUENCY (0.0f) +#define AL_RING_MODULATOR_MAX_FREQUENCY (8000.0f) +#define AL_RING_MODULATOR_DEFAULT_FREQUENCY (440.0f) + +#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF (0.0f) +#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF (24000.0f) +#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f) + +#define AL_RING_MODULATOR_SINUSOID (0) +#define AL_RING_MODULATOR_SAWTOOTH (1) +#define AL_RING_MODULATOR_SQUARE (2) + +#define AL_RING_MODULATOR_MIN_WAVEFORM (0) +#define AL_RING_MODULATOR_MAX_WAVEFORM (2) +#define AL_RING_MODULATOR_DEFAULT_WAVEFORM (0) + +/* Autowah effect */ +#define AL_AUTOWAH_MIN_ATTACK_TIME (0.0001f) +#define AL_AUTOWAH_MAX_ATTACK_TIME (1.0f) +#define AL_AUTOWAH_DEFAULT_ATTACK_TIME (0.06f) + +#define AL_AUTOWAH_MIN_RELEASE_TIME (0.0001f) +#define AL_AUTOWAH_MAX_RELEASE_TIME (1.0f) +#define AL_AUTOWAH_DEFAULT_RELEASE_TIME (0.06f) + +#define AL_AUTOWAH_MIN_RESONANCE (2.0f) +#define AL_AUTOWAH_MAX_RESONANCE (1000.0f) +#define AL_AUTOWAH_DEFAULT_RESONANCE (1000.0f) + +#define AL_AUTOWAH_MIN_PEAK_GAIN (0.00003f) +#define AL_AUTOWAH_MAX_PEAK_GAIN (31621.0f) +#define AL_AUTOWAH_DEFAULT_PEAK_GAIN (11.22f) + +/* Compressor effect */ +#define AL_COMPRESSOR_MIN_ONOFF (0) +#define AL_COMPRESSOR_MAX_ONOFF (1) +#define AL_COMPRESSOR_DEFAULT_ONOFF (1) + +/* Equalizer effect */ +#define AL_EQUALIZER_MIN_LOW_GAIN (0.126f) +#define AL_EQUALIZER_MAX_LOW_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_LOW_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_LOW_CUTOFF (50.0f) +#define AL_EQUALIZER_MAX_LOW_CUTOFF (800.0f) +#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF (200.0f) + +#define AL_EQUALIZER_MIN_MID1_GAIN (0.126f) +#define AL_EQUALIZER_MAX_MID1_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_MID1_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_MID1_CENTER (200.0f) +#define AL_EQUALIZER_MAX_MID1_CENTER (3000.0f) +#define AL_EQUALIZER_DEFAULT_MID1_CENTER (500.0f) + +#define AL_EQUALIZER_MIN_MID1_WIDTH (0.01f) +#define AL_EQUALIZER_MAX_MID1_WIDTH (1.0f) +#define AL_EQUALIZER_DEFAULT_MID1_WIDTH (1.0f) + +#define AL_EQUALIZER_MIN_MID2_GAIN (0.126f) +#define AL_EQUALIZER_MAX_MID2_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_MID2_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_MID2_CENTER (1000.0f) +#define AL_EQUALIZER_MAX_MID2_CENTER (8000.0f) +#define AL_EQUALIZER_DEFAULT_MID2_CENTER (3000.0f) + +#define AL_EQUALIZER_MIN_MID2_WIDTH (0.01f) +#define AL_EQUALIZER_MAX_MID2_WIDTH (1.0f) +#define AL_EQUALIZER_DEFAULT_MID2_WIDTH (1.0f) + +#define AL_EQUALIZER_MIN_HIGH_GAIN (0.126f) +#define AL_EQUALIZER_MAX_HIGH_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_HIGH_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_HIGH_CUTOFF (4000.0f) +#define AL_EQUALIZER_MAX_HIGH_CUTOFF (16000.0f) +#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF (6000.0f) + + +/* Source parameter value ranges and defaults. */ +#define AL_MIN_AIR_ABSORPTION_FACTOR (0.0f) +#define AL_MAX_AIR_ABSORPTION_FACTOR (10.0f) +#define AL_DEFAULT_AIR_ABSORPTION_FACTOR (0.0f) + +#define AL_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_MIN_CONE_OUTER_GAINHF (0.0f) +#define AL_MAX_CONE_OUTER_GAINHF (1.0f) +#define AL_DEFAULT_CONE_OUTER_GAINHF (1.0f) + +#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO AL_FALSE +#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO AL_TRUE +#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO AL_TRUE + +#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_FALSE +#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE +#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE + +#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE +#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE +#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE + + +/* Listener parameter value ranges and defaults. */ +#define AL_MIN_METERS_PER_UNIT FLT_MIN +#define AL_MAX_METERS_PER_UNIT FLT_MAX +#define AL_DEFAULT_METERS_PER_UNIT (1.0f) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AL_EFX_H */ diff --git a/project/jni/openal/src/Alc/ALc.c b/project/jni/openal/src/Alc/ALc.c new file mode 100644 index 000000000..cc3896567 --- /dev/null +++ b/project/jni/openal/src/Alc/ALc.c @@ -0,0 +1,2179 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "alMain.h" +#include "alSource.h" +#include "AL/al.h" +#include "AL/alc.h" +#include "alThunk.h" +#include "alSource.h" +#include "alBuffer.h" +#include "alAuxEffectSlot.h" +#include "alDatabuffer.h" +#include "bs2b.h" +#include "alu.h" + + +#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +typedef struct BackendInfo { + const char *name; + void (*Init)(BackendFuncs*); + void (*Deinit)(void); + void (*Probe)(int); + BackendFuncs Funcs; +} BackendInfo; +static BackendInfo BackendList[] = { +#ifdef HAVE_PULSEAUDIO + { "pulse", alc_pulse_init, alc_pulse_deinit, alc_pulse_probe, EmptyFuncs }, +#endif +#ifdef HAVE_ALSA + { "alsa", alc_alsa_init, alc_alsa_deinit, alc_alsa_probe, EmptyFuncs }, +#endif +#ifdef HAVE_OSS + { "oss", alc_oss_init, alc_oss_deinit, alc_oss_probe, EmptyFuncs }, +#endif +#ifdef HAVE_SOLARIS + { "solaris", alc_solaris_init, alc_solaris_deinit, alc_solaris_probe, EmptyFuncs }, +#endif +#ifdef HAVE_DSOUND + { "dsound", alcDSoundInit, alcDSoundDeinit, alcDSoundProbe, EmptyFuncs }, +#endif +#ifdef HAVE_WINMM + { "winmm", alcWinMMInit, alcWinMMDeinit, alcWinMMProbe, EmptyFuncs }, +#endif +#ifdef HAVE_PORTAUDIO + { "port", alc_pa_init, alc_pa_deinit, alc_pa_probe, EmptyFuncs }, +#endif +#ifdef HAVE_ANDROID + { "android", alc_android_init, alc_android_deinit, alc_android_probe, EmptyFuncs }, +#endif + + { "null", alc_null_init, alc_null_deinit, alc_null_probe, EmptyFuncs }, +#ifdef HAVE_WAVE + { "wave", alc_wave_init, alc_wave_deinit, alc_wave_probe, EmptyFuncs }, +#endif + + { NULL, NULL, NULL, NULL, EmptyFuncs } +}; +#undef EmptyFuncs + +/////////////////////////////////////////////////////// + +#define ALC_EFX_MAJOR_VERSION 0x20001 +#define ALC_EFX_MINOR_VERSION 0x20002 +#define ALC_MAX_AUXILIARY_SENDS 0x20003 + +/////////////////////////////////////////////////////// +// STRING and EXTENSIONS + +typedef struct ALCfunction { + const ALCchar *funcName; + ALCvoid *address; +} ALCfunction; + +typedef struct ALCenums { + const ALCchar *enumName; + ALCenum value; +} ALCenums; + + +static const ALCfunction alcFunctions[] = { + { "alcCreateContext", (ALCvoid *) alcCreateContext }, + { "alcMakeContextCurrent", (ALCvoid *) alcMakeContextCurrent }, + { "alcProcessContext", (ALCvoid *) alcProcessContext }, + { "alcSuspendContext", (ALCvoid *) alcSuspendContext }, + { "alcDestroyContext", (ALCvoid *) alcDestroyContext }, + { "alcGetCurrentContext", (ALCvoid *) alcGetCurrentContext }, + { "alcGetContextsDevice", (ALCvoid *) alcGetContextsDevice }, + { "alcOpenDevice", (ALCvoid *) alcOpenDevice }, + { "alcCloseDevice", (ALCvoid *) alcCloseDevice }, + { "alcGetError", (ALCvoid *) alcGetError }, + { "alcIsExtensionPresent", (ALCvoid *) alcIsExtensionPresent }, + { "alcGetProcAddress", (ALCvoid *) alcGetProcAddress }, + { "alcGetEnumValue", (ALCvoid *) alcGetEnumValue }, + { "alcGetString", (ALCvoid *) alcGetString }, + { "alcGetIntegerv", (ALCvoid *) alcGetIntegerv }, + { "alcCaptureOpenDevice", (ALCvoid *) alcCaptureOpenDevice }, + { "alcCaptureCloseDevice", (ALCvoid *) alcCaptureCloseDevice }, + { "alcCaptureStart", (ALCvoid *) alcCaptureStart }, + { "alcCaptureStop", (ALCvoid *) alcCaptureStop }, + { "alcCaptureSamples", (ALCvoid *) alcCaptureSamples }, + + { "alcSetThreadContext", (ALCvoid *) alcSetThreadContext }, + { "alcGetThreadContext", (ALCvoid *) alcGetThreadContext }, + + { "alEnable", (ALCvoid *) alEnable }, + { "alDisable", (ALCvoid *) alDisable }, + { "alIsEnabled", (ALCvoid *) alIsEnabled }, + { "alGetString", (ALCvoid *) alGetString }, + { "alGetBooleanv", (ALCvoid *) alGetBooleanv }, + { "alGetIntegerv", (ALCvoid *) alGetIntegerv }, + { "alGetFloatv", (ALCvoid *) alGetFloatv }, + { "alGetDoublev", (ALCvoid *) alGetDoublev }, + { "alGetBoolean", (ALCvoid *) alGetBoolean }, + { "alGetInteger", (ALCvoid *) alGetInteger }, + { "alGetFloat", (ALCvoid *) alGetFloat }, + { "alGetDouble", (ALCvoid *) alGetDouble }, + { "alGetError", (ALCvoid *) alGetError }, + { "alIsExtensionPresent", (ALCvoid *) alIsExtensionPresent }, + { "alGetProcAddress", (ALCvoid *) alGetProcAddress }, + { "alGetEnumValue", (ALCvoid *) alGetEnumValue }, + { "alListenerf", (ALCvoid *) alListenerf }, + { "alListener3f", (ALCvoid *) alListener3f }, + { "alListenerfv", (ALCvoid *) alListenerfv }, + { "alListeneri", (ALCvoid *) alListeneri }, + { "alListener3i", (ALCvoid *) alListener3i }, + { "alListeneriv", (ALCvoid *) alListeneriv }, + { "alGetListenerf", (ALCvoid *) alGetListenerf }, + { "alGetListener3f", (ALCvoid *) alGetListener3f }, + { "alGetListenerfv", (ALCvoid *) alGetListenerfv }, + { "alGetListeneri", (ALCvoid *) alGetListeneri }, + { "alGetListener3i", (ALCvoid *) alGetListener3i }, + { "alGetListeneriv", (ALCvoid *) alGetListeneriv }, + { "alGenSources", (ALCvoid *) alGenSources }, + { "alDeleteSources", (ALCvoid *) alDeleteSources }, + { "alIsSource", (ALCvoid *) alIsSource }, + { "alSourcef", (ALCvoid *) alSourcef }, + { "alSource3f", (ALCvoid *) alSource3f }, + { "alSourcefv", (ALCvoid *) alSourcefv }, + { "alSourcei", (ALCvoid *) alSourcei }, + { "alSource3i", (ALCvoid *) alSource3i }, + { "alSourceiv", (ALCvoid *) alSourceiv }, + { "alGetSourcef", (ALCvoid *) alGetSourcef }, + { "alGetSource3f", (ALCvoid *) alGetSource3f }, + { "alGetSourcefv", (ALCvoid *) alGetSourcefv }, + { "alGetSourcei", (ALCvoid *) alGetSourcei }, + { "alGetSource3i", (ALCvoid *) alGetSource3i }, + { "alGetSourceiv", (ALCvoid *) alGetSourceiv }, + { "alSourcePlayv", (ALCvoid *) alSourcePlayv }, + { "alSourceStopv", (ALCvoid *) alSourceStopv }, + { "alSourceRewindv", (ALCvoid *) alSourceRewindv }, + { "alSourcePausev", (ALCvoid *) alSourcePausev }, + { "alSourcePlay", (ALCvoid *) alSourcePlay }, + { "alSourceStop", (ALCvoid *) alSourceStop }, + { "alSourceRewind", (ALCvoid *) alSourceRewind }, + { "alSourcePause", (ALCvoid *) alSourcePause }, + { "alSourceQueueBuffers", (ALCvoid *) alSourceQueueBuffers }, + { "alSourceUnqueueBuffers", (ALCvoid *) alSourceUnqueueBuffers }, + { "alGenBuffers", (ALCvoid *) alGenBuffers }, + { "alDeleteBuffers", (ALCvoid *) alDeleteBuffers }, + { "alIsBuffer", (ALCvoid *) alIsBuffer }, + { "alBufferData", (ALCvoid *) alBufferData }, + { "alBufferf", (ALCvoid *) alBufferf }, + { "alBuffer3f", (ALCvoid *) alBuffer3f }, + { "alBufferfv", (ALCvoid *) alBufferfv }, + { "alBufferi", (ALCvoid *) alBufferi }, + { "alBuffer3i", (ALCvoid *) alBuffer3i }, + { "alBufferiv", (ALCvoid *) alBufferiv }, + { "alGetBufferf", (ALCvoid *) alGetBufferf }, + { "alGetBuffer3f", (ALCvoid *) alGetBuffer3f }, + { "alGetBufferfv", (ALCvoid *) alGetBufferfv }, + { "alGetBufferi", (ALCvoid *) alGetBufferi }, + { "alGetBuffer3i", (ALCvoid *) alGetBuffer3i }, + { "alGetBufferiv", (ALCvoid *) alGetBufferiv }, + { "alDopplerFactor", (ALCvoid *) alDopplerFactor }, + { "alDopplerVelocity", (ALCvoid *) alDopplerVelocity }, + { "alSpeedOfSound", (ALCvoid *) alSpeedOfSound }, + { "alDistanceModel", (ALCvoid *) alDistanceModel }, + + { "alGenFilters", (ALCvoid *) alGenFilters }, + { "alDeleteFilters", (ALCvoid *) alDeleteFilters }, + { "alIsFilter", (ALCvoid *) alIsFilter }, + { "alFilteri", (ALCvoid *) alFilteri }, + { "alFilteriv", (ALCvoid *) alFilteriv }, + { "alFilterf", (ALCvoid *) alFilterf }, + { "alFilterfv", (ALCvoid *) alFilterfv }, + { "alGetFilteri", (ALCvoid *) alGetFilteri }, + { "alGetFilteriv", (ALCvoid *) alGetFilteriv }, + { "alGetFilterf", (ALCvoid *) alGetFilterf }, + { "alGetFilterfv", (ALCvoid *) alGetFilterfv }, + + { "alGenEffects", (ALCvoid *) alGenEffects }, + { "alDeleteEffects", (ALCvoid *) alDeleteEffects }, + { "alIsEffect", (ALCvoid *) alIsEffect }, + { "alEffecti", (ALCvoid *) alEffecti }, + { "alEffectiv", (ALCvoid *) alEffectiv }, + { "alEffectf", (ALCvoid *) alEffectf }, + { "alEffectfv", (ALCvoid *) alEffectfv }, + { "alGetEffecti", (ALCvoid *) alGetEffecti }, + { "alGetEffectiv", (ALCvoid *) alGetEffectiv }, + { "alGetEffectf", (ALCvoid *) alGetEffectf }, + { "alGetEffectfv", (ALCvoid *) alGetEffectfv }, + + { "alGenAuxiliaryEffectSlots", (ALCvoid *) alGenAuxiliaryEffectSlots}, + { "alDeleteAuxiliaryEffectSlots",(ALCvoid *) alDeleteAuxiliaryEffectSlots}, + { "alIsAuxiliaryEffectSlot", (ALCvoid *) alIsAuxiliaryEffectSlot }, + { "alAuxiliaryEffectSloti", (ALCvoid *) alAuxiliaryEffectSloti }, + { "alAuxiliaryEffectSlotiv", (ALCvoid *) alAuxiliaryEffectSlotiv }, + { "alAuxiliaryEffectSlotf", (ALCvoid *) alAuxiliaryEffectSlotf }, + { "alAuxiliaryEffectSlotfv", (ALCvoid *) alAuxiliaryEffectSlotfv }, + { "alGetAuxiliaryEffectSloti", (ALCvoid *) alGetAuxiliaryEffectSloti}, + { "alGetAuxiliaryEffectSlotiv", (ALCvoid *) alGetAuxiliaryEffectSlotiv}, + { "alGetAuxiliaryEffectSlotf", (ALCvoid *) alGetAuxiliaryEffectSlotf}, + { "alGetAuxiliaryEffectSlotfv", (ALCvoid *) alGetAuxiliaryEffectSlotfv}, + + { "alBufferSubDataEXT", (ALCvoid *) alBufferSubDataEXT }, + + { "alGenDatabuffersEXT", (ALCvoid *) alGenDatabuffersEXT }, + { "alDeleteDatabuffersEXT", (ALCvoid *) alDeleteDatabuffersEXT }, + { "alIsDatabufferEXT", (ALCvoid *) alIsDatabufferEXT }, + { "alDatabufferDataEXT", (ALCvoid *) alDatabufferDataEXT }, + { "alDatabufferSubDataEXT", (ALCvoid *) alDatabufferSubDataEXT }, + { "alGetDatabufferSubDataEXT", (ALCvoid *) alGetDatabufferSubDataEXT}, + { "alDatabufferfEXT", (ALCvoid *) alDatabufferfEXT }, + { "alDatabufferfvEXT", (ALCvoid *) alDatabufferfvEXT }, + { "alDatabufferiEXT", (ALCvoid *) alDatabufferiEXT }, + { "alDatabufferivEXT", (ALCvoid *) alDatabufferivEXT }, + { "alGetDatabufferfEXT", (ALCvoid *) alGetDatabufferfEXT }, + { "alGetDatabufferfvEXT", (ALCvoid *) alGetDatabufferfvEXT }, + { "alGetDatabufferiEXT", (ALCvoid *) alGetDatabufferiEXT }, + { "alGetDatabufferivEXT", (ALCvoid *) alGetDatabufferivEXT }, + { "alSelectDatabufferEXT", (ALCvoid *) alSelectDatabufferEXT }, + { "alMapDatabufferEXT", (ALCvoid *) alMapDatabufferEXT }, + { "alUnmapDatabufferEXT", (ALCvoid *) alUnmapDatabufferEXT }, + + { NULL, (ALCvoid *) NULL } +}; + +static const ALCenums enumeration[] = { + // Types + { "ALC_INVALID", ALC_INVALID }, + { "ALC_FALSE", ALC_FALSE }, + { "ALC_TRUE", ALC_TRUE }, + + // ALC Properties + { "ALC_MAJOR_VERSION", ALC_MAJOR_VERSION }, + { "ALC_MINOR_VERSION", ALC_MINOR_VERSION }, + { "ALC_ATTRIBUTES_SIZE", ALC_ATTRIBUTES_SIZE }, + { "ALC_ALL_ATTRIBUTES", ALC_ALL_ATTRIBUTES }, + { "ALC_DEFAULT_DEVICE_SPECIFIER", ALC_DEFAULT_DEVICE_SPECIFIER }, + { "ALC_DEVICE_SPECIFIER", ALC_DEVICE_SPECIFIER }, + { "ALC_ALL_DEVICES_SPECIFIER", ALC_ALL_DEVICES_SPECIFIER }, + { "ALC_DEFAULT_ALL_DEVICES_SPECIFIER", ALC_DEFAULT_ALL_DEVICES_SPECIFIER }, + { "ALC_EXTENSIONS", ALC_EXTENSIONS }, + { "ALC_FREQUENCY", ALC_FREQUENCY }, + { "ALC_REFRESH", ALC_REFRESH }, + { "ALC_SYNC", ALC_SYNC }, + { "ALC_MONO_SOURCES", ALC_MONO_SOURCES }, + { "ALC_STEREO_SOURCES", ALC_STEREO_SOURCES }, + { "ALC_CAPTURE_DEVICE_SPECIFIER", ALC_CAPTURE_DEVICE_SPECIFIER }, + { "ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER", ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER}, + { "ALC_CAPTURE_SAMPLES", ALC_CAPTURE_SAMPLES }, + { "ALC_CONNECTED", ALC_CONNECTED }, + + // EFX Properties + { "ALC_EFX_MAJOR_VERSION", ALC_EFX_MAJOR_VERSION }, + { "ALC_EFX_MINOR_VERSION", ALC_EFX_MINOR_VERSION }, + { "ALC_MAX_AUXILIARY_SENDS", ALC_MAX_AUXILIARY_SENDS }, + + // ALC Error Message + { "ALC_NO_ERROR", ALC_NO_ERROR }, + { "ALC_INVALID_DEVICE", ALC_INVALID_DEVICE }, + { "ALC_INVALID_CONTEXT", ALC_INVALID_CONTEXT }, + { "ALC_INVALID_ENUM", ALC_INVALID_ENUM }, + { "ALC_INVALID_VALUE", ALC_INVALID_VALUE }, + { "ALC_OUT_OF_MEMORY", ALC_OUT_OF_MEMORY }, + { NULL, (ALCenum)0 } +}; +// Error strings +static const ALCchar alcNoError[] = "No Error"; +static const ALCchar alcErrInvalidDevice[] = "Invalid Device"; +static const ALCchar alcErrInvalidContext[] = "Invalid Context"; +static const ALCchar alcErrInvalidEnum[] = "Invalid Enum"; +static const ALCchar alcErrInvalidValue[] = "Invalid Value"; +static const ALCchar alcErrOutOfMemory[] = "Out of Memory"; + +/* Device lists. Sizes only include the first ending null character, not the + * second */ +static ALCchar *alcDeviceList; +static size_t alcDeviceListSize; +static ALCchar *alcAllDeviceList; +static size_t alcAllDeviceListSize; +static ALCchar *alcCaptureDeviceList; +static size_t alcCaptureDeviceListSize; +// Default is always the first in the list +static ALCchar *alcDefaultDeviceSpecifier; +static ALCchar *alcDefaultAllDeviceSpecifier; +static ALCchar *alcCaptureDefaultDeviceSpecifier; + + +static const ALCchar alcNoDeviceExtList[] = + "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " + "ALC_EXT_thread_local_context"; +static const ALCchar alcExtensionList[] = + "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " + "ALC_EXT_disconnect ALC_EXT_EFX ALC_EXT_thread_local_context"; +static const ALCint alcMajorVersion = 1; +static const ALCint alcMinorVersion = 1; + +static const ALCint alcEFXMajorVersion = 1; +static const ALCint alcEFXMinorVersion = 0; + +/////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////// +// Global Variables + +static ALCdevice *g_pDeviceList = NULL; +static ALCuint g_ulDeviceCount = 0; + +static CRITICAL_SECTION g_csMutex; + +// Context List +static ALCcontext *g_pContextList = NULL; +static ALCuint g_ulContextCount = 0; + +// Thread-local current context +static tls_type LocalContext; +// Process-wide current context +static ALCcontext *GlobalContext; + +// Context Error +static ALCenum g_eLastNullDeviceError = ALC_NO_ERROR; + +// Default context extensions +static const ALchar alExtList[] = + "AL_EXTX_buffer_sub_data AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE " + "AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXTX_loop_points " + "AL_EXT_MCFORMATS AL_EXT_MULAW AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET " + "AL_EXTX_sample_buffer_object AL_EXT_source_distance_model " + "AL_LOKI_quadriphonic"; + +// Mixing Priority Level +static ALint RTPrioLevel; + +// Resampler Quality +resampler_t DefaultResampler; + +// Output Log File +static FILE *LogFile; + +/////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////// +// ALC Related helper functions +#ifdef _WIN32 +static void alc_init(void); +static void alc_deinit(void); + +BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) +{ + (void)lpReserved; + + // Perform actions based on the reason for calling. + switch(ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hModule); + alc_init(); + break; + + case DLL_PROCESS_DETACH: + alc_deinit(); + break; + } + return TRUE; +} +#else +#ifdef HAVE_GCC_DESTRUCTOR +static void alc_init(void) __attribute__((constructor)); +static void alc_deinit(void) __attribute__((destructor)); +#endif +#endif + +static void alc_init(void) +{ + int i; + const char *devs, *str; + + str = getenv("ALSOFT_LOGFILE"); + if(str && str[0]) + { + LogFile = fopen(str, "w"); + if(!LogFile) + fprintf(stderr, "AL lib: Failed to open log file '%s'\n", str); + } + if(!LogFile) + LogFile = stderr; + + InitializeCriticalSection(&g_csMutex); + ALTHUNK_INIT(); + ReadALConfig(); + + tls_create(&LocalContext); + + RTPrioLevel = GetConfigValueInt(NULL, "rt-prio", 0); + + DefaultResampler = GetConfigValueInt(NULL, "resampler", RESAMPLER_DEFAULT); + if(DefaultResampler >= RESAMPLER_MAX || DefaultResampler <= RESAMPLER_MIN) + DefaultResampler = RESAMPLER_DEFAULT; + + devs = GetConfigValue(NULL, "drivers", ""); + if(devs[0]) + { + int n; + size_t len; + const char *next = devs; + int endlist, delitem; + + i = 0; + do { + devs = next; + next = strchr(devs, ','); + + delitem = (devs[0] == '-'); + if(devs[0] == '-') devs++; + + if(!devs[0] || devs[0] == ',') + { + endlist = 0; + continue; + } + endlist = 1; + + len = (next ? ((size_t)(next-devs)) : strlen(devs)); + for(n = i;BackendList[n].Init;n++) + { + if(len == strlen(BackendList[n].name) && + strncmp(BackendList[n].name, devs, len) == 0) + { + if(delitem) + { + do { + BackendList[n] = BackendList[n+1]; + ++n; + } while(BackendList[n].Init); + } + else + { + BackendInfo Bkp = BackendList[n]; + while(n > i) + { + BackendList[n] = BackendList[n-1]; + --n; + } + BackendList[n] = Bkp; + + i++; + } + break; + } + } + } while(next++); + + if(endlist) + { + BackendList[i].name = NULL; + BackendList[i].Init = NULL; + BackendList[i].Deinit = NULL; + BackendList[i].Probe = NULL; + } + } + + for(i = 0;BackendList[i].Init;i++) + BackendList[i].Init(&BackendList[i].Funcs); + + str = GetConfigValue(NULL, "excludefx", ""); + if(str[0]) + { + const struct { + const char *name; + int type; + } EffectList[] = { + { "eaxreverb", EAXREVERB }, + { "reverb", REVERB }, + { "echo", ECHO }, + { "modulator", MODULATOR }, + { NULL, 0 } + }; + int n; + size_t len; + const char *next = str; + + do { + str = next; + next = strchr(str, ','); + + if(!str[0] || next == str) + continue; + + len = (next ? ((size_t)(next-str)) : strlen(str)); + for(n = 0;EffectList[n].name;n++) + { + if(len == strlen(EffectList[n].name) && + strncmp(EffectList[n].name, str, len) == 0) + DisabledEffects[EffectList[n].type] = AL_TRUE; + } + } while(next++); + } +} + +static void alc_deinit(void) +{ + int i; + + ReleaseALC(); + + for(i = 0;BackendList[i].Deinit;i++) + BackendList[i].Deinit(); + + if(LogFile != stderr) + fclose(LogFile); + LogFile = NULL; + + tls_delete(LocalContext); + + FreeALConfig(); + ALTHUNK_EXIT(); + DeleteCriticalSection(&g_csMutex); +} + + +static void ProbeDeviceList() +{ + ALint i; + + free(alcDeviceList); alcDeviceList = NULL; + alcDeviceListSize = 0; + + for(i = 0;BackendList[i].Probe;i++) + BackendList[i].Probe(DEVICE_PROBE); +} + +static void ProbeAllDeviceList() +{ + ALint i; + + free(alcAllDeviceList); alcAllDeviceList = NULL; + alcAllDeviceListSize = 0; + + for(i = 0;BackendList[i].Probe;i++) + BackendList[i].Probe(ALL_DEVICE_PROBE); +} + +static void ProbeCaptureDeviceList() +{ + ALint i; + + free(alcCaptureDeviceList); alcCaptureDeviceList = NULL; + alcCaptureDeviceListSize = 0; + + for(i = 0;BackendList[i].Probe;i++) + BackendList[i].Probe(CAPTURE_DEVICE_PROBE); +} + + +#define DECL_APPEND_LIST_FUNC(type) \ +void Append##type##List(const ALCchar *name) \ +{ \ + size_t len = strlen(name); \ + void *temp; \ + \ + if(len == 0) \ + return; \ + \ + temp = realloc(alc##type##List, alc##type##ListSize + len + 2); \ + if(!temp) \ + { \ + AL_PRINT("Realloc failed to add %s!\n", name); \ + return; \ + } \ + alc##type##List = temp; \ + sprintf(alc##type##List+alc##type##ListSize, "%s", name); \ + alc##type##ListSize += len+1; \ + alc##type##List[alc##type##ListSize] = 0; \ +} + +DECL_APPEND_LIST_FUNC(Device) +DECL_APPEND_LIST_FUNC(AllDevice) +DECL_APPEND_LIST_FUNC(CaptureDevice) + + +void al_print(const char *fname, unsigned int line, const char *fmt, ...) +{ + const char *fn; + char str[256]; + int i; + + fn = strrchr(fname, '/'); + if(!fn) fn = strrchr(fname, '\\');; + if(!fn) fn = fname; + else fn += 1; + + i = snprintf(str, sizeof(str), "AL lib: %s:%d: ", fn, line); + if(i < (int)sizeof(str) && i > 0) + { + va_list ap; + va_start(ap, fmt); + vsnprintf(str+i, sizeof(str)-i, fmt, ap); + va_end(ap); + } + str[sizeof(str)-1] = 0; + +#ifdef ANDROID + __android_log_write(ANDROID_LOG_WARN, "OpenAL", str); +#endif + fprintf(LogFile, "%s", str); + fflush(LogFile); +} + +void SetRTPriority(void) +{ + ALboolean failed; + +#ifdef _WIN32 + if(RTPrioLevel > 0) + failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + else + failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); +#elif defined(HAVE_PTHREAD_SETSCHEDPARAM) + struct sched_param param; + + if(RTPrioLevel > 0) + { + /* Use the minimum real-time priority possible for now (on Linux this + * should be 1 for SCHED_RR) */ + param.sched_priority = sched_get_priority_min(SCHED_RR); + failed = !!pthread_setschedparam(pthread_self(), SCHED_RR, ¶m); + } + else + { + param.sched_priority = 0; + failed = !!pthread_setschedparam(pthread_self(), SCHED_OTHER, ¶m); + } +#else + /* Real-time priority not available */ + failed = (RTPrioLevel>0); +#endif + if(failed) + AL_PRINT("Failed to set priority level for thread\n"); +} + + +void InitUIntMap(UIntMap *map) +{ + map->array = NULL; + map->size = 0; + map->maxsize = 0; +} + +void ResetUIntMap(UIntMap *map) +{ + free(map->array); + map->array = NULL; + map->size = 0; + map->maxsize = 0; +} + +ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value) +{ + ALsizei pos = 0; + + if(map->size > 0) + { + ALsizei low = 0; + ALsizei high = map->size - 1; + while(low < high) + { + ALsizei mid = low + (high-low)/2; + if(map->array[mid].key < key) + low = mid + 1; + else + high = mid; + } + if(map->array[low].key < key) + low++; + pos = low; + } + + if(pos == map->size || map->array[pos].key != key) + { + if(map->size == map->maxsize) + { + ALvoid *temp; + ALsizei newsize; + + newsize = (map->maxsize ? (map->maxsize<<1) : 4); + if(newsize < map->maxsize) + return AL_OUT_OF_MEMORY; + + temp = realloc(map->array, newsize*sizeof(map->array[0])); + if(!temp) return AL_OUT_OF_MEMORY; + map->array = temp; + map->maxsize = newsize; + } + + map->size++; + if(pos < map->size-1) + memmove(&map->array[pos+1], &map->array[pos], + (map->size-1-pos)*sizeof(map->array[0])); + } + map->array[pos].key = key; + map->array[pos].value = value; + + return AL_NO_ERROR; +} + +void RemoveUIntMapKey(UIntMap *map, ALuint key) +{ + if(map->size > 0) + { + ALsizei low = 0; + ALsizei high = map->size - 1; + while(low < high) + { + ALsizei mid = low + (high-low)/2; + if(map->array[mid].key < key) + low = mid + 1; + else + high = mid; + } + if(map->array[low].key == key) + { + if(low < map->size-1) + memmove(&map->array[low], &map->array[low+1], + (map->size-1-low)*sizeof(map->array[0])); + map->size--; + } + } +} + + +/* + IsDevice + + Check pDevice is a valid Device pointer +*/ +static ALCboolean IsDevice(ALCdevice *pDevice) +{ + ALCdevice *pTempDevice; + + SuspendContext(NULL); + + pTempDevice = g_pDeviceList; + while(pTempDevice && pTempDevice != pDevice) + pTempDevice = pTempDevice->next; + + ProcessContext(NULL); + + return (pTempDevice ? ALC_TRUE : ALC_FALSE); +} + +/* + IsContext + + Check pContext is a valid Context pointer +*/ +static ALCboolean IsContext(ALCcontext *pContext) +{ + ALCcontext *pTempContext; + + SuspendContext(NULL); + + pTempContext = g_pContextList; + while (pTempContext && pTempContext != pContext) + pTempContext = pTempContext->next; + + ProcessContext(NULL); + + return (pTempContext ? ALC_TRUE : ALC_FALSE); +} + + +/* + alcSetError + + Store latest ALC Error +*/ +ALCvoid alcSetError(ALCdevice *device, ALenum errorCode) +{ + if(IsDevice(device)) + device->LastError = errorCode; + else + g_eLastNullDeviceError = errorCode; +} + + +/* + SuspendContext + + Thread-safe entry +*/ +ALCvoid SuspendContext(ALCcontext *pContext) +{ + (void)pContext; + EnterCriticalSection(&g_csMutex); +} + + +/* + ProcessContext + + Thread-safe exit +*/ +ALCvoid ProcessContext(ALCcontext *pContext) +{ + (void)pContext; + LeaveCriticalSection(&g_csMutex); +} + + +/* + GetContextSuspended + + Returns the currently active Context, in a locked state +*/ +ALCcontext *GetContextSuspended(void) +{ + ALCcontext *pContext = NULL; + + SuspendContext(NULL); + + pContext = tls_get(LocalContext); + if(pContext && !IsContext(pContext)) + { + tls_set(LocalContext, NULL); + pContext = NULL; + } + if(!pContext) + pContext = GlobalContext; + + if(pContext) + SuspendContext(pContext); + + ProcessContext(NULL); + + return pContext; +} + + +/* + InitContext + + Initialize Context variables +*/ +static ALvoid InitContext(ALCcontext *pContext) +{ + //Initialise listener + pContext->Listener.Gain = 1.0f; + pContext->Listener.MetersPerUnit = 1.0f; + pContext->Listener.Position[0] = 0.0f; + pContext->Listener.Position[1] = 0.0f; + pContext->Listener.Position[2] = 0.0f; + pContext->Listener.Velocity[0] = 0.0f; + pContext->Listener.Velocity[1] = 0.0f; + pContext->Listener.Velocity[2] = 0.0f; + pContext->Listener.Forward[0] = 0.0f; + pContext->Listener.Forward[1] = 0.0f; + pContext->Listener.Forward[2] = -1.0f; + pContext->Listener.Up[0] = 0.0f; + pContext->Listener.Up[1] = 1.0f; + pContext->Listener.Up[2] = 0.0f; + + //Validate pContext + pContext->LastError = AL_NO_ERROR; + pContext->Suspended = AL_FALSE; + pContext->ActiveSourceCount = 0; + InitUIntMap(&pContext->SourceMap); + InitUIntMap(&pContext->EffectSlotMap); + + //Set globals + pContext->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED; + pContext->SourceDistanceModel = AL_FALSE; + pContext->DopplerFactor = 1.0f; + pContext->DopplerVelocity = 1.0f; + pContext->flSpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; + + pContext->ExtensionList = alExtList; +} + + +/* + ExitContext + + Clean up Context, destroy any remaining Sources +*/ +static ALCvoid ExitContext(ALCcontext *pContext) +{ + //Invalidate context + pContext->LastError = AL_NO_ERROR; +} + +/////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////// +// ALC Functions calls + + +// This should probably move to another c file but for now ... +ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize) +{ + ALCboolean DeviceFound = ALC_FALSE; + ALCdevice *device = NULL; + ALCint i; + + if(SampleSize <= 0) + { + alcSetError(NULL, ALC_INVALID_VALUE); + return NULL; + } + + if(deviceName && !deviceName[0]) + deviceName = NULL; + + device = calloc(1, sizeof(ALCdevice)); + if(!device) + { + alcSetError(NULL, ALC_OUT_OF_MEMORY); + return NULL; + } + + //Validate device + device->Connected = ALC_TRUE; + device->IsCaptureDevice = AL_TRUE; + + device->szDeviceName = NULL; + + device->Frequency = frequency; + device->Format = format; + device->UpdateSize = SampleSize; + device->NumUpdates = 1; + + SuspendContext(NULL); + for(i = 0;BackendList[i].Init;i++) + { + device->Funcs = &BackendList[i].Funcs; + if(ALCdevice_OpenCapture(device, deviceName)) + { + device->next = g_pDeviceList; + g_pDeviceList = device; + g_ulDeviceCount++; + + DeviceFound = ALC_TRUE; + break; + } + } + ProcessContext(NULL); + + if(!DeviceFound) + { + alcSetError(NULL, ALC_INVALID_VALUE); + free(device); + device = NULL; + } + + return device; +} + +ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *pDevice) +{ + ALCdevice **list; + + if(!IsDevice(pDevice) || !pDevice->IsCaptureDevice) + { + alcSetError(pDevice, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + + SuspendContext(NULL); + + list = &g_pDeviceList; + while(*list != pDevice) + list = &(*list)->next; + + *list = (*list)->next; + g_ulDeviceCount--; + + ProcessContext(NULL); + + ALCdevice_CloseCapture(pDevice); + + free(pDevice->szDeviceName); + pDevice->szDeviceName = NULL; + + free(pDevice); + + return ALC_TRUE; +} + +ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) +{ + SuspendContext(NULL); + if(!IsDevice(device) || !device->IsCaptureDevice) + alcSetError(device, ALC_INVALID_DEVICE); + else if(device->Connected) + ALCdevice_StartCapture(device); + ProcessContext(NULL); +} + +ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) +{ + SuspendContext(NULL); + if(!IsDevice(device) || !device->IsCaptureDevice) + alcSetError(device, ALC_INVALID_DEVICE); + else + ALCdevice_StopCapture(device); + ProcessContext(NULL); +} + +ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) +{ + SuspendContext(NULL); + if(!IsDevice(device) || !device->IsCaptureDevice) + alcSetError(device, ALC_INVALID_DEVICE); + else + ALCdevice_CaptureSamples(device, buffer, samples); + ProcessContext(NULL); +} + +/* + alcGetError + + Return last ALC generated error code +*/ +ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) +{ + ALCenum errorCode; + + if(IsDevice(device)) + { + errorCode = device->LastError; + device->LastError = ALC_NO_ERROR; + } + else + { + errorCode = g_eLastNullDeviceError; + g_eLastNullDeviceError = ALC_NO_ERROR; + } + return errorCode; +} + + +/* + alcSuspendContext + + Not functional +*/ +ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *pContext) +{ + SuspendContext(NULL); + if(IsContext(pContext)) + pContext->Suspended = AL_TRUE; + ProcessContext(NULL); +} + + +/* + alcProcessContext + + Not functional +*/ +ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *pContext) +{ + SuspendContext(NULL); + if(IsContext(pContext)) + pContext->Suspended = AL_FALSE; + ProcessContext(NULL); +} + + +/* + alcGetString + + Returns information about the Device, and error strings +*/ +ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *pDevice,ALCenum param) +{ + const ALCchar *value = NULL; + + switch (param) + { + case ALC_NO_ERROR: + value = alcNoError; + break; + + case ALC_INVALID_ENUM: + value = alcErrInvalidEnum; + break; + + case ALC_INVALID_VALUE: + value = alcErrInvalidValue; + break; + + case ALC_INVALID_DEVICE: + value = alcErrInvalidDevice; + break; + + case ALC_INVALID_CONTEXT: + value = alcErrInvalidContext; + break; + + case ALC_OUT_OF_MEMORY: + value = alcErrOutOfMemory; + break; + + case ALC_DEVICE_SPECIFIER: + if(IsDevice(pDevice)) + value = pDevice->szDeviceName; + else + { + ProbeDeviceList(); + value = alcDeviceList; + } + break; + + case ALC_ALL_DEVICES_SPECIFIER: + ProbeAllDeviceList(); + value = alcAllDeviceList; + break; + + case ALC_CAPTURE_DEVICE_SPECIFIER: + if(IsDevice(pDevice)) + value = pDevice->szDeviceName; + else + { + ProbeCaptureDeviceList(); + value = alcCaptureDeviceList; + } + break; + + /* Default devices are always first in the list */ + case ALC_DEFAULT_DEVICE_SPECIFIER: + if(!alcDeviceList) + ProbeDeviceList(); + + free(alcDefaultDeviceSpecifier); + alcDefaultDeviceSpecifier = strdup(alcDeviceList ? alcDeviceList : ""); + if(!alcDefaultDeviceSpecifier) + alcSetError(pDevice, ALC_OUT_OF_MEMORY); + value = alcDefaultDeviceSpecifier; + break; + + case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: + if(!alcAllDeviceList) + ProbeAllDeviceList(); + + free(alcDefaultAllDeviceSpecifier); + alcDefaultAllDeviceSpecifier = strdup(alcAllDeviceList ? + alcAllDeviceList : ""); + if(!alcDefaultAllDeviceSpecifier) + alcSetError(pDevice, ALC_OUT_OF_MEMORY); + value = alcDefaultAllDeviceSpecifier; + break; + + case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: + if(!alcCaptureDeviceList) + ProbeCaptureDeviceList(); + + free(alcCaptureDefaultDeviceSpecifier); + alcCaptureDefaultDeviceSpecifier = strdup(alcCaptureDeviceList ? + alcCaptureDeviceList : ""); + if(!alcCaptureDefaultDeviceSpecifier) + alcSetError(pDevice, ALC_OUT_OF_MEMORY); + value = alcCaptureDefaultDeviceSpecifier; + break; + + case ALC_EXTENSIONS: + if(IsDevice(pDevice)) + value = alcExtensionList; + else + value = alcNoDeviceExtList; + break; + + default: + alcSetError(pDevice, ALC_INVALID_ENUM); + break; + } + + return value; +} + + +/* + alcGetIntegerv + + Returns information about the Device and the version of Open AL +*/ +ALC_API ALCvoid ALC_APIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsizei size,ALCint *data) +{ + if(size == 0 || data == NULL) + { + alcSetError(device, ALC_INVALID_VALUE); + return; + } + + if(IsDevice(device) && device->IsCaptureDevice) + { + SuspendContext(NULL); + + // Capture device + switch (param) + { + case ALC_CAPTURE_SAMPLES: + *data = ALCdevice_AvailableSamples(device); + break; + + case ALC_CONNECTED: + *data = device->Connected; + break; + + default: + alcSetError(device, ALC_INVALID_ENUM); + break; + } + + ProcessContext(NULL); + return; + } + + // Playback Device + switch (param) + { + case ALC_MAJOR_VERSION: + *data = alcMajorVersion; + break; + + case ALC_MINOR_VERSION: + *data = alcMinorVersion; + break; + + case ALC_EFX_MAJOR_VERSION: + *data = alcEFXMajorVersion; + break; + + case ALC_EFX_MINOR_VERSION: + *data = alcEFXMinorVersion; + break; + + case ALC_MAX_AUXILIARY_SENDS: + if(!IsDevice(device)) + alcSetError(device, ALC_INVALID_DEVICE); + else + *data = device->NumAuxSends; + break; + + case ALC_ATTRIBUTES_SIZE: + if(!IsDevice(device)) + alcSetError(device, ALC_INVALID_DEVICE); + else + *data = 13; + break; + + case ALC_ALL_ATTRIBUTES: + if(!IsDevice(device)) + alcSetError(device, ALC_INVALID_DEVICE); + else if (size < 13) + alcSetError(device, ALC_INVALID_VALUE); + else + { + int i = 0; + + SuspendContext(NULL); + data[i++] = ALC_FREQUENCY; + data[i++] = device->Frequency; + + data[i++] = ALC_REFRESH; + data[i++] = device->Frequency / device->UpdateSize; + + data[i++] = ALC_SYNC; + data[i++] = ALC_FALSE; + + data[i++] = ALC_MONO_SOURCES; + data[i++] = device->NumMonoSources; + + data[i++] = ALC_STEREO_SOURCES; + data[i++] = device->NumStereoSources; + + data[i++] = ALC_MAX_AUXILIARY_SENDS; + data[i++] = device->NumAuxSends; + + data[i++] = 0; + ProcessContext(NULL); + } + break; + + case ALC_FREQUENCY: + if(!IsDevice(device)) + alcSetError(device, ALC_INVALID_DEVICE); + else + *data = device->Frequency; + break; + + case ALC_REFRESH: + if(!IsDevice(device)) + alcSetError(device, ALC_INVALID_DEVICE); + else + *data = device->Frequency / device->UpdateSize; + break; + + case ALC_SYNC: + if(!IsDevice(device)) + alcSetError(device, ALC_INVALID_DEVICE); + else + *data = ALC_FALSE; + break; + + case ALC_MONO_SOURCES: + if(!IsDevice(device)) + alcSetError(device, ALC_INVALID_DEVICE); + else + *data = device->NumMonoSources; + break; + + case ALC_STEREO_SOURCES: + if(!IsDevice(device)) + alcSetError(device, ALC_INVALID_DEVICE); + else + *data = device->NumStereoSources; + break; + + case ALC_CONNECTED: + if(!IsDevice(device)) + alcSetError(device, ALC_INVALID_DEVICE); + else + *data = device->Connected; + break; + + default: + alcSetError(device, ALC_INVALID_ENUM); + break; + } +} + + +/* + alcIsExtensionPresent + + Determines if there is support for a particular extension +*/ +ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName) +{ + ALCboolean bResult = ALC_FALSE; + const char *ptr; + size_t len; + + if(!extName) + { + alcSetError(device, ALC_INVALID_VALUE); + return ALC_FALSE; + } + + len = strlen(extName); + ptr = (IsDevice(device) ? alcExtensionList : alcNoDeviceExtList); + while(ptr && *ptr) + { + if(strncasecmp(ptr, extName, len) == 0 && + (ptr[len] == '\0' || isspace(ptr[len]))) + { + bResult = ALC_TRUE; + break; + } + if((ptr=strchr(ptr, ' ')) != NULL) + { + do { + ++ptr; + } while(isspace(*ptr)); + } + } + + return bResult; +} + + +/* + alcGetProcAddress + + Retrieves the function address for a particular extension function +*/ +ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName) +{ + ALsizei i = 0; + + if(!funcName) + { + alcSetError(device, ALC_INVALID_VALUE); + return NULL; + } + + while(alcFunctions[i].funcName && strcmp(alcFunctions[i].funcName,funcName) != 0) + i++; + return alcFunctions[i].address; +} + + +/* + alcGetEnumValue + + Get the value for a particular ALC Enumerated Value +*/ +ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName) +{ + ALsizei i = 0; + + if(!enumName) + { + alcSetError(device, ALC_INVALID_VALUE); + return (ALCenum)0; + } + + while(enumeration[i].enumName && strcmp(enumeration[i].enumName,enumName) != 0) + i++; + return enumeration[i].value; +} + + +/* + alcCreateContext + + Create and attach a Context to a particular Device. +*/ +ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList) +{ + ALCcontext *ALContext; + ALboolean running; + ALuint attrIdx; + void *temp; + ALuint i; + + SuspendContext(NULL); + + if(!IsDevice(device) || device->IsCaptureDevice || !device->Connected) + { + alcSetError(device, ALC_INVALID_DEVICE); + ProcessContext(NULL); + return NULL; + } + + running = ((device->NumContexts > 0) ? AL_TRUE : AL_FALSE); + + // Reset Context Last Error code + device->LastError = ALC_NO_ERROR; + + // Check for attributes + if(attrList && attrList[0]) + { + ALCuint freq, numMono, numStereo, numSends; + + // If a context is already running on the device, stop playback so the + // device attributes can be updated + if(running) + { + ProcessContext(NULL); + ALCdevice_StopPlayback(device); + SuspendContext(NULL); + running = AL_FALSE; + } + + freq = device->Frequency; + numMono = device->NumMonoSources; + numStereo = device->NumStereoSources; + numSends = device->NumAuxSends; + + attrIdx = 0; + while(attrList[attrIdx]) + { + if(attrList[attrIdx] == ALC_FREQUENCY && + !ConfigValueExists(NULL, "frequency")) + { + freq = attrList[attrIdx + 1]; + if(freq < 8000) + freq = 8000; + } + + if(attrList[attrIdx] == ALC_STEREO_SOURCES) + { + numStereo = attrList[attrIdx + 1]; + if(numStereo > device->MaxNoOfSources) + numStereo = device->MaxNoOfSources; + + numMono = device->MaxNoOfSources - numStereo; + } + + if(attrList[attrIdx] == ALC_MAX_AUXILIARY_SENDS && + !ConfigValueExists(NULL, "sends")) + { + numSends = attrList[attrIdx + 1]; + if(numSends > MAX_SENDS) + numSends = MAX_SENDS; + } + + attrIdx += 2; + } + + device->UpdateSize = (ALuint64)device->UpdateSize * freq / + device->Frequency; + + device->Frequency = freq; + device->NumMonoSources = numMono; + device->NumStereoSources = numStereo; + device->NumAuxSends = numSends; + } + + if(running == AL_FALSE && ALCdevice_ResetPlayback(device) == ALC_FALSE) + { + alcSetError(device, ALC_INVALID_DEVICE); + aluHandleDisconnect(device); + ProcessContext(NULL); + return NULL; + } + aluInitPanning(device); + + for(i = 0;i < device->NumContexts;i++) + { + ALCcontext *context = device->Contexts[i]; + ALsizei pos; + + SuspendContext(context); + for(pos = 0;pos < context->EffectSlotMap.size;pos++) + { + ALeffectslot *slot = context->EffectSlotMap.array[pos].value; + if(!slot->EffectState) + continue; + + if(ALEffect_DeviceUpdate(slot->EffectState, device) == AL_FALSE) + { + alcSetError(device, ALC_INVALID_DEVICE); + aluHandleDisconnect(device); + ProcessContext(context); + ProcessContext(NULL); + ALCdevice_StopPlayback(device); + return NULL; + } + ALEffect_Update(slot->EffectState, context, &slot->effect); + } + + for(pos = 0;pos < context->SourceMap.size;pos++) + { + ALsource *source = context->SourceMap.array[pos].value; + ALuint s = device->NumAuxSends; + while(s < MAX_SENDS) + { + if(source->Send[s].Slot) + source->Send[s].Slot->refcount--; + source->Send[s].Slot = NULL; + source->Send[s].WetFilter.type = 0; + source->Send[s].WetFilter.filter = 0; + s++; + } + source->NeedsUpdate = AL_TRUE; + } + ProcessContext(context); + } + + if(device->Bs2bLevel > 0 && device->Bs2bLevel <= 6) + { + if(!device->Bs2b) + { + device->Bs2b = calloc(1, sizeof(*device->Bs2b)); + bs2b_clear(device->Bs2b); + } + bs2b_set_srate(device->Bs2b, device->Frequency); + bs2b_set_level(device->Bs2b, device->Bs2bLevel); + } + else + { + free(device->Bs2b); + device->Bs2b = NULL; + } + + if(aluChannelsFromFormat(device->Format) <= 2) + { + device->HeadDampen = GetConfigValueFloat(NULL, "head_dampen", DEFAULT_HEAD_DAMPEN); + device->HeadDampen = __min(device->HeadDampen, 1.0f); + device->HeadDampen = __max(device->HeadDampen, 0.0f); + } + else + device->HeadDampen = 0.0f; + + temp = realloc(device->Contexts, (device->NumContexts+1) * sizeof(*device->Contexts)); + if(!temp) + { + alcSetError(device, ALC_OUT_OF_MEMORY); + ProcessContext(NULL); + return NULL; + } + device->Contexts = temp; + + ALContext = calloc(1, sizeof(ALCcontext)); + if(ALContext) + { + ALContext->MaxActiveSources = 256; + ALContext->ActiveSources = malloc(sizeof(*ALContext->ActiveSources) * + ALContext->MaxActiveSources); + } + if(!ALContext || !ALContext->ActiveSources) + { + free(ALContext); + alcSetError(device, ALC_OUT_OF_MEMORY); + ProcessContext(NULL); + return NULL; + } + + device->Contexts[device->NumContexts++] = ALContext; + ALContext->Device = device; + + InitContext(ALContext); + + ALContext->next = g_pContextList; + g_pContextList = ALContext; + g_ulContextCount++; + + ProcessContext(NULL); + + return ALContext; +} + + +/* + alcDestroyContext + + Remove a Context +*/ +ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) +{ + ALCdevice *Device; + ALCcontext **list; + ALuint i; + + if(!IsContext(context)) + { + alcSetError(NULL, ALC_INVALID_CONTEXT); + return; + } + + Device = context->Device; + + if(Device->NumContexts == 1) + ALCdevice_StopPlayback(Device); + + SuspendContext(NULL); + + if(context == GlobalContext) + GlobalContext = NULL; + + for(i = 0;i < Device->NumContexts-1;i++) + { + if(Device->Contexts[i] == context) + { + Device->Contexts[i] = Device->Contexts[Device->NumContexts-1]; + break; + } + } + Device->NumContexts--; + + // Lock context + SuspendContext(context); + + if(context->SourceMap.size > 0) + { +#ifdef _DEBUG + AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", context->SourceMap.size); +#endif + ReleaseALSources(context); + } + ResetUIntMap(&context->SourceMap); + + if(context->EffectSlotMap.size > 0) + { +#ifdef _DEBUG + AL_PRINT("alcDestroyContext(): deleting %d AuxiliaryEffectSlot(s)\n", context->EffectSlotMap.size); +#endif + ReleaseALAuxiliaryEffectSlots(context); + } + ResetUIntMap(&context->EffectSlotMap); + + free(context->ActiveSources); + context->ActiveSources = NULL; + context->MaxActiveSources = 0; + context->ActiveSourceCount = 0; + + list = &g_pContextList; + while(*list != context) + list = &(*list)->next; + + *list = (*list)->next; + g_ulContextCount--; + + // Unlock context + ProcessContext(context); + ProcessContext(NULL); + + ExitContext(context); + + // Free memory (MUST do this after ProcessContext) + memset(context, 0, sizeof(ALCcontext)); + free(context); +} + + +/* + alcGetCurrentContext + + Returns the currently active Context +*/ +ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(ALCvoid) +{ + ALCcontext *pContext; + + if((pContext=GetContextSuspended()) != NULL) + ProcessContext(pContext); + + return pContext; +} + +/* + alcGetThreadContext + + Returns the currently active thread-local Context +*/ +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) +{ + ALCcontext *pContext = NULL; + + SuspendContext(NULL); + + pContext = tls_get(LocalContext); + if(pContext && !IsContext(pContext)) + { + tls_set(LocalContext, NULL); + pContext = NULL; + } + + ProcessContext(NULL); + + return pContext; +} + + +/* + alcGetContextsDevice + + Returns the Device that a particular Context is attached to +*/ +ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *pContext) +{ + ALCdevice *pDevice = NULL; + + SuspendContext(NULL); + if(IsContext(pContext)) + pDevice = pContext->Device; + else + alcSetError(NULL, ALC_INVALID_CONTEXT); + ProcessContext(NULL); + + return pDevice; +} + + +/* + alcMakeContextCurrent + + Makes the given Context the active Context +*/ +ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) +{ + ALboolean bReturn = AL_TRUE; + + SuspendContext(NULL); + + // context must be a valid Context or NULL + if(context == NULL || IsContext(context)) + { + GlobalContext = context; + tls_set(LocalContext, NULL); + } + else + { + alcSetError(NULL, ALC_INVALID_CONTEXT); + bReturn = AL_FALSE; + } + + ProcessContext(NULL); + + return bReturn; +} + +/* + alcSetThreadContext + + Makes the given Context the active Context for the current thread +*/ +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) +{ + ALboolean bReturn = AL_TRUE; + + SuspendContext(NULL); + + // context must be a valid Context or NULL + if(context == NULL || IsContext(context)) + tls_set(LocalContext, context); + else + { + alcSetError(NULL, ALC_INVALID_CONTEXT); + bReturn = AL_FALSE; + } + + ProcessContext(NULL); + + return bReturn; +} + + +// Sets the default channel order used by most non-WaveFormatEx-based APIs +void SetDefaultChannelOrder(ALCdevice *device) +{ + switch(aluChannelsFromFormat(device->Format)) + { + case 1: device->DevChannels[FRONT_CENTER] = 0; break; + + case 2: device->DevChannels[FRONT_LEFT] = 0; + device->DevChannels[FRONT_RIGHT] = 1; break; + + case 4: device->DevChannels[FRONT_LEFT] = 0; + device->DevChannels[FRONT_RIGHT] = 1; + device->DevChannels[BACK_LEFT] = 2; + device->DevChannels[BACK_RIGHT] = 3; break; + + case 6: device->DevChannels[FRONT_LEFT] = 0; + device->DevChannels[FRONT_RIGHT] = 1; + device->DevChannels[BACK_LEFT] = 2; + device->DevChannels[BACK_RIGHT] = 3; + device->DevChannels[FRONT_CENTER] = 4; + device->DevChannels[LFE] = 5; break; + + case 7: device->DevChannels[FRONT_LEFT] = 0; + device->DevChannels[FRONT_RIGHT] = 1; + device->DevChannels[FRONT_CENTER] = 2; + device->DevChannels[LFE] = 3; + device->DevChannels[BACK_CENTER] = 4; + device->DevChannels[SIDE_LEFT] = 5; + device->DevChannels[SIDE_RIGHT] = 6; break; + + case 8: device->DevChannels[FRONT_LEFT] = 0; + device->DevChannels[FRONT_RIGHT] = 1; + device->DevChannels[BACK_LEFT] = 2; + device->DevChannels[BACK_RIGHT] = 3; + device->DevChannels[FRONT_CENTER] = 4; + device->DevChannels[LFE] = 5; + device->DevChannels[SIDE_LEFT] = 6; + device->DevChannels[SIDE_RIGHT] = 7; break; + } +} +// Sets the default order used by WaveFormatEx +void SetDefaultWFXChannelOrder(ALCdevice *device) +{ + switch(aluChannelsFromFormat(device->Format)) + { + case 1: device->DevChannels[FRONT_CENTER] = 0; break; + + case 2: device->DevChannels[FRONT_LEFT] = 0; + device->DevChannels[FRONT_RIGHT] = 1; break; + + case 4: device->DevChannels[FRONT_LEFT] = 0; + device->DevChannels[FRONT_RIGHT] = 1; + device->DevChannels[BACK_LEFT] = 2; + device->DevChannels[BACK_RIGHT] = 3; break; + + case 6: device->DevChannels[FRONT_LEFT] = 0; + device->DevChannels[FRONT_RIGHT] = 1; + device->DevChannels[FRONT_CENTER] = 2; + device->DevChannels[LFE] = 3; + device->DevChannels[BACK_LEFT] = 4; + device->DevChannels[BACK_RIGHT] = 5; break; + + case 7: device->DevChannels[FRONT_LEFT] = 0; + device->DevChannels[FRONT_RIGHT] = 1; + device->DevChannels[FRONT_CENTER] = 2; + device->DevChannels[LFE] = 3; + device->DevChannels[BACK_CENTER] = 4; + device->DevChannels[SIDE_LEFT] = 5; + device->DevChannels[SIDE_RIGHT] = 6; break; + + case 8: device->DevChannels[FRONT_LEFT] = 0; + device->DevChannels[FRONT_RIGHT] = 1; + device->DevChannels[FRONT_CENTER] = 2; + device->DevChannels[LFE] = 3; + device->DevChannels[BACK_LEFT] = 4; + device->DevChannels[BACK_RIGHT] = 5; + device->DevChannels[SIDE_LEFT] = 6; + device->DevChannels[SIDE_RIGHT] = 7; break; + } +} + +static ALenum GetFormatFromString(const char *str) +{ + if(strcasecmp(str, "AL_FORMAT_MONO32") == 0) return AL_FORMAT_MONO_FLOAT32; + if(strcasecmp(str, "AL_FORMAT_STEREO32") == 0) return AL_FORMAT_STEREO_FLOAT32; + if(strcasecmp(str, "AL_FORMAT_QUAD32") == 0) return AL_FORMAT_QUAD32; + if(strcasecmp(str, "AL_FORMAT_51CHN32") == 0) return AL_FORMAT_51CHN32; + if(strcasecmp(str, "AL_FORMAT_61CHN32") == 0) return AL_FORMAT_61CHN32; + if(strcasecmp(str, "AL_FORMAT_71CHN32") == 0) return AL_FORMAT_71CHN32; + + if(strcasecmp(str, "AL_FORMAT_MONO16") == 0) return AL_FORMAT_MONO16; + if(strcasecmp(str, "AL_FORMAT_STEREO16") == 0) return AL_FORMAT_STEREO16; + if(strcasecmp(str, "AL_FORMAT_QUAD16") == 0) return AL_FORMAT_QUAD16; + if(strcasecmp(str, "AL_FORMAT_51CHN16") == 0) return AL_FORMAT_51CHN16; + if(strcasecmp(str, "AL_FORMAT_61CHN16") == 0) return AL_FORMAT_61CHN16; + if(strcasecmp(str, "AL_FORMAT_71CHN16") == 0) return AL_FORMAT_71CHN16; + + if(strcasecmp(str, "AL_FORMAT_MONO8") == 0) return AL_FORMAT_MONO8; + if(strcasecmp(str, "AL_FORMAT_STEREO8") == 0) return AL_FORMAT_STEREO8; + if(strcasecmp(str, "AL_FORMAT_QUAD8") == 0) return AL_FORMAT_QUAD8; + if(strcasecmp(str, "AL_FORMAT_51CHN8") == 0) return AL_FORMAT_51CHN8; + if(strcasecmp(str, "AL_FORMAT_61CHN8") == 0) return AL_FORMAT_61CHN8; + if(strcasecmp(str, "AL_FORMAT_71CHN8") == 0) return AL_FORMAT_71CHN8; + + AL_PRINT("Unknown format: \"%s\"\n", str); + return AL_FORMAT_STEREO16; +} + +/* + alcOpenDevice + + Open the Device specified. +*/ +ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) +{ + ALboolean bDeviceFound = AL_FALSE; + const ALCchar *fmt; + ALCdevice *device; + ALint i; + + if(deviceName && !deviceName[0]) + deviceName = NULL; + + device = calloc(1, sizeof(ALCdevice)); + if(!device) + { + alcSetError(NULL, ALC_OUT_OF_MEMORY); + return NULL; + } + + //Validate device + device->Connected = ALC_TRUE; + device->IsCaptureDevice = AL_FALSE; + device->LastError = ALC_NO_ERROR; + + device->Bs2b = NULL; + device->szDeviceName = NULL; + + device->Contexts = NULL; + device->NumContexts = 0; + + InitUIntMap(&device->BufferMap); + InitUIntMap(&device->EffectMap); + InitUIntMap(&device->FilterMap); + InitUIntMap(&device->DatabufferMap); + + //Set output format + device->Frequency = GetConfigValueInt(NULL, "frequency", SWMIXER_OUTPUT_RATE); + if(device->Frequency < 8000) + device->Frequency = 8000; + + fmt = GetConfigValue(NULL, "format", "AL_FORMAT_STEREO16"); + device->Format = GetFormatFromString(fmt); + + device->NumUpdates = GetConfigValueInt(NULL, "periods", 4); + if(device->NumUpdates < 2) + device->NumUpdates = 4; + + device->UpdateSize = GetConfigValueInt(NULL, "period_size", 1024); + if(device->UpdateSize <= 0) + device->UpdateSize = 1024; + + device->MaxNoOfSources = GetConfigValueInt(NULL, "sources", 256); + if((ALint)device->MaxNoOfSources <= 0) + device->MaxNoOfSources = 256; + + device->AuxiliaryEffectSlotMax = GetConfigValueInt(NULL, "slots", 4); + if((ALint)device->AuxiliaryEffectSlotMax <= 0) + device->AuxiliaryEffectSlotMax = 4; + + device->NumStereoSources = 1; + device->NumMonoSources = device->MaxNoOfSources - device->NumStereoSources; + + device->NumAuxSends = GetConfigValueInt(NULL, "sends", MAX_SENDS); + if(device->NumAuxSends > MAX_SENDS) + device->NumAuxSends = MAX_SENDS; + + device->Bs2bLevel = GetConfigValueInt(NULL, "cf_level", 0); + + device->HeadDampen = 0.0f; + + // Find a playback device to open + SuspendContext(NULL); + for(i = 0;BackendList[i].Init;i++) + { + device->Funcs = &BackendList[i].Funcs; + if(ALCdevice_OpenPlayback(device, deviceName)) + { + device->next = g_pDeviceList; + g_pDeviceList = device; + g_ulDeviceCount++; + + bDeviceFound = AL_TRUE; + break; + } + } + ProcessContext(NULL); + + if(!bDeviceFound) + { + // No suitable output device found + alcSetError(NULL, ALC_INVALID_VALUE); + free(device); + device = NULL; + } + + return device; +} + + +/* + alcCloseDevice + + Close the specified Device +*/ +ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *pDevice) +{ + ALCdevice **list; + + if(!IsDevice(pDevice) || pDevice->IsCaptureDevice) + { + alcSetError(pDevice, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + + SuspendContext(NULL); + + list = &g_pDeviceList; + while(*list != pDevice) + list = &(*list)->next; + + *list = (*list)->next; + g_ulDeviceCount--; + + ProcessContext(NULL); + + if(pDevice->NumContexts > 0) + { +#ifdef _DEBUG + AL_PRINT("alcCloseDevice(): destroying %u Context(s)\n", pDevice->NumContexts); +#endif + while(pDevice->NumContexts > 0) + alcDestroyContext(pDevice->Contexts[0]); + } + ALCdevice_ClosePlayback(pDevice); + + if(pDevice->BufferMap.size > 0) + { +#ifdef _DEBUG + AL_PRINT("alcCloseDevice(): deleting %d Buffer(s)\n", pDevice->BufferMap.size); +#endif + ReleaseALBuffers(pDevice); + } + ResetUIntMap(&pDevice->BufferMap); + + if(pDevice->EffectMap.size > 0) + { +#ifdef _DEBUG + AL_PRINT("alcCloseDevice(): deleting %d Effect(s)\n", pDevice->EffectMap.size); +#endif + ReleaseALEffects(pDevice); + } + ResetUIntMap(&pDevice->EffectMap); + + if(pDevice->FilterMap.size > 0) + { +#ifdef _DEBUG + AL_PRINT("alcCloseDevice(): deleting %d Filter(s)\n", pDevice->FilterMap.size); +#endif + ReleaseALFilters(pDevice); + } + ResetUIntMap(&pDevice->FilterMap); + + if(pDevice->DatabufferMap.size > 0) + { +#ifdef _DEBUG + AL_PRINT("alcCloseDevice(): deleting %d Databuffer(s)\n", pDevice->DatabufferMap.size); +#endif + ReleaseALDatabuffers(pDevice); + } + ResetUIntMap(&pDevice->DatabufferMap); + + free(pDevice->Bs2b); + pDevice->Bs2b = NULL; + + free(pDevice->szDeviceName); + pDevice->szDeviceName = NULL; + + free(pDevice->Contexts); + pDevice->Contexts = NULL; + + //Release device structure + memset(pDevice, 0, sizeof(ALCdevice)); + free(pDevice); + + return ALC_TRUE; +} + + +ALCvoid ReleaseALC(ALCvoid) +{ + free(alcDeviceList); alcDeviceList = NULL; + alcDeviceListSize = 0; + free(alcAllDeviceList); alcAllDeviceList = NULL; + alcAllDeviceListSize = 0; + free(alcCaptureDeviceList); alcCaptureDeviceList = NULL; + alcCaptureDeviceListSize = 0; + + free(alcDefaultDeviceSpecifier); + alcDefaultDeviceSpecifier = NULL; + free(alcDefaultAllDeviceSpecifier); + alcDefaultAllDeviceSpecifier = NULL; + free(alcCaptureDefaultDeviceSpecifier); + alcCaptureDefaultDeviceSpecifier = NULL; + +#ifdef _DEBUG + if(g_ulDeviceCount > 0) + AL_PRINT("exit(): closing %u Device%s\n", g_ulDeviceCount, (g_ulDeviceCount>1)?"s":""); +#endif + + while(g_pDeviceList) + { + if(g_pDeviceList->IsCaptureDevice) + alcCaptureCloseDevice(g_pDeviceList); + else + alcCloseDevice(g_pDeviceList); + } +} + +/////////////////////////////////////////////////////// diff --git a/project/jni/openal/src/Alc/ALu.c b/project/jni/openal/src/Alc/ALu.c new file mode 100644 index 000000000..15de0abea --- /dev/null +++ b/project/jni/openal/src/Alc/ALu.c @@ -0,0 +1,1655 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" +#include "alSource.h" +#include "alBuffer.h" +#include "alThunk.h" +#include "alListener.h" +#include "alAuxEffectSlot.h" +#include "alu.h" +#include "bs2b.h" + +#define FRACTIONBITS 14 +#define FRACTIONMASK ((1L<>8)+128; +} + + +static __inline ALvoid aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector) +{ + outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1]; + outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2]; + outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0]; +} + +static __inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2) +{ + return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] + + inVector1[2]*inVector2[2]; +} + +static __inline ALvoid aluNormalize(ALfloat *inVector) +{ + ALfloat length, inverse_length; + + length = aluSqrt(aluDotproduct(inVector, inVector)); + if(length != 0.0f) + { + inverse_length = 1.0f/length; + inVector[0] *= inverse_length; + inVector[1] *= inverse_length; + inVector[2] *= inverse_length; + } +} + +static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat w,ALfloat matrix[4][4]) +{ + ALfloat temp[4] = { + vector[0], vector[1], vector[2], w + }; + + vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0]; + vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1]; + vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2]; +} + +static ALvoid SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[OUTPUTCHANNELS], + Channel Speaker2Chan[OUTPUTCHANNELS], ALint chans) +{ + char layout_str[256]; + char *confkey, *next; + char *sep, *end; + Channel val; + int i; + + strncpy(layout_str, GetConfigValue(NULL, name, ""), sizeof(layout_str)); + layout_str[255] = 0; + + if(!layout_str[0]) + return; + + next = confkey = layout_str; + while(next && *next) + { + confkey = next; + next = strchr(confkey, ','); + if(next) + { + *next = 0; + do { + next++; + } while(isspace(*next) || *next == ','); + } + + sep = strchr(confkey, '='); + if(!sep || confkey == sep) + continue; + + end = sep - 1; + while(isspace(*end) && end != confkey) + end--; + *(++end) = 0; + + if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0) + val = FRONT_LEFT; + else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0) + val = FRONT_RIGHT; + else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0) + val = FRONT_CENTER; + else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0) + val = BACK_LEFT; + else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0) + val = BACK_RIGHT; + else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0) + val = BACK_CENTER; + else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0) + val = SIDE_LEFT; + else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0) + val = SIDE_RIGHT; + else + { + AL_PRINT("Unknown speaker for %s: \"%s\"\n", name, confkey); + continue; + } + + *(sep++) = 0; + while(isspace(*sep)) + sep++; + + for(i = 0;i < chans;i++) + { + if(Speaker2Chan[i] == val) + { + long angle = strtol(sep, NULL, 10); + if(angle >= -180 && angle <= 180) + SpeakerAngle[i] = angle * M_PI/180.0f; + else + AL_PRINT("Invalid angle for speaker \"%s\": %ld\n", confkey, angle); + break; + } + } + } + + for(i = 0;i < chans;i++) + { + int min = i; + int i2; + + for(i2 = i+1;i2 < chans;i2++) + { + if(SpeakerAngle[i2] < SpeakerAngle[min]) + min = i2; + } + + if(min != i) + { + ALfloat tmpf; + Channel tmpc; + + tmpf = SpeakerAngle[i]; + SpeakerAngle[i] = SpeakerAngle[min]; + SpeakerAngle[min] = tmpf; + + tmpc = Speaker2Chan[i]; + Speaker2Chan[i] = Speaker2Chan[min]; + Speaker2Chan[min] = tmpc; + } + } +} + +static __inline ALfloat aluLUTpos2Angle(ALint pos) +{ + if(pos < QUADRANT_NUM) + return aluAtan((ALfloat)pos / (ALfloat)(QUADRANT_NUM - pos)); + if(pos < 2 * QUADRANT_NUM) + return M_PI_2 + aluAtan((ALfloat)(pos - QUADRANT_NUM) / (ALfloat)(2 * QUADRANT_NUM - pos)); + if(pos < 3 * QUADRANT_NUM) + return aluAtan((ALfloat)(pos - 2 * QUADRANT_NUM) / (ALfloat)(3 * QUADRANT_NUM - pos)) - M_PI; + return aluAtan((ALfloat)(pos - 3 * QUADRANT_NUM) / (ALfloat)(4 * QUADRANT_NUM - pos)) - M_PI_2; +} + +ALvoid aluInitPanning(ALCdevice *Device) +{ + ALfloat SpeakerAngle[OUTPUTCHANNELS]; + Channel *Speaker2Chan; + ALfloat Alpha, Theta; + ALint pos, offset; + ALuint s, s2; + + for(s = 0;s < OUTPUTCHANNELS;s++) + { + for(s2 = 0;s2 < OUTPUTCHANNELS;s2++) + Device->ChannelMatrix[s][s2] = ((s==s2) ? 1.0f : 0.0f); + } + + Speaker2Chan = Device->Speaker2Chan; + switch(Device->Format) + { + case AL_FORMAT_MONO8: + case AL_FORMAT_MONO16: + case AL_FORMAT_MONO_FLOAT32: + Device->DuplicateStereo = AL_FALSE; + Device->ChannelMatrix[FRONT_LEFT][FRONT_CENTER] = aluSqrt(0.5); + Device->ChannelMatrix[FRONT_RIGHT][FRONT_CENTER] = aluSqrt(0.5); + Device->ChannelMatrix[SIDE_LEFT][FRONT_CENTER] = aluSqrt(0.5); + Device->ChannelMatrix[SIDE_RIGHT][FRONT_CENTER] = aluSqrt(0.5); + Device->ChannelMatrix[BACK_LEFT][FRONT_CENTER] = aluSqrt(0.5); + Device->ChannelMatrix[BACK_RIGHT][FRONT_CENTER] = aluSqrt(0.5); + Device->ChannelMatrix[BACK_CENTER][FRONT_CENTER] = 1.0f; + Device->NumChan = 1; + Speaker2Chan[0] = FRONT_CENTER; + SpeakerAngle[0] = 0.0f * M_PI/180.0f; + break; + + case AL_FORMAT_STEREO8: + case AL_FORMAT_STEREO16: + case AL_FORMAT_STEREO_FLOAT32: + Device->DuplicateStereo = AL_FALSE; + Device->ChannelMatrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5); + Device->ChannelMatrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5); + Device->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = 1.0f; + Device->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = 1.0f; + Device->ChannelMatrix[BACK_LEFT][FRONT_LEFT] = 1.0f; + Device->ChannelMatrix[BACK_RIGHT][FRONT_RIGHT] = 1.0f; + Device->ChannelMatrix[BACK_CENTER][FRONT_LEFT] = aluSqrt(0.5); + Device->ChannelMatrix[BACK_CENTER][FRONT_RIGHT] = aluSqrt(0.5); + Device->NumChan = 2; + Speaker2Chan[0] = FRONT_LEFT; + Speaker2Chan[1] = FRONT_RIGHT; + SpeakerAngle[0] = -90.0f * M_PI/180.0f; + SpeakerAngle[1] = 90.0f * M_PI/180.0f; + SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan); + break; + + case AL_FORMAT_QUAD8: + case AL_FORMAT_QUAD16: + case AL_FORMAT_QUAD32: + Device->DuplicateStereo = GetConfigValueBool(NULL, "stereodup", 0); + Device->ChannelMatrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5); + Device->ChannelMatrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5); + Device->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5); + Device->ChannelMatrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5); + Device->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5); + Device->ChannelMatrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5); + Device->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5); + Device->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5); + Device->NumChan = 4; + Speaker2Chan[0] = BACK_LEFT; + Speaker2Chan[1] = FRONT_LEFT; + Speaker2Chan[2] = FRONT_RIGHT; + Speaker2Chan[3] = BACK_RIGHT; + SpeakerAngle[0] = -135.0f * M_PI/180.0f; + SpeakerAngle[1] = -45.0f * M_PI/180.0f; + SpeakerAngle[2] = 45.0f * M_PI/180.0f; + SpeakerAngle[3] = 135.0f * M_PI/180.0f; + SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan); + break; + + case AL_FORMAT_51CHN8: + case AL_FORMAT_51CHN16: + case AL_FORMAT_51CHN32: + Device->DuplicateStereo = GetConfigValueBool(NULL, "stereodup", 0); + Device->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5); + Device->ChannelMatrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5); + Device->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5); + Device->ChannelMatrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5); + Device->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5); + Device->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5); + Device->NumChan = 5; + Speaker2Chan[0] = BACK_LEFT; + Speaker2Chan[1] = FRONT_LEFT; + Speaker2Chan[2] = FRONT_CENTER; + Speaker2Chan[3] = FRONT_RIGHT; + Speaker2Chan[4] = BACK_RIGHT; + SpeakerAngle[0] = -110.0f * M_PI/180.0f; + SpeakerAngle[1] = -30.0f * M_PI/180.0f; + SpeakerAngle[2] = 0.0f * M_PI/180.0f; + SpeakerAngle[3] = 30.0f * M_PI/180.0f; + SpeakerAngle[4] = 110.0f * M_PI/180.0f; + SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan); + break; + + case AL_FORMAT_61CHN8: + case AL_FORMAT_61CHN16: + case AL_FORMAT_61CHN32: + Device->DuplicateStereo = GetConfigValueBool(NULL, "stereodup", 0); + Device->ChannelMatrix[BACK_LEFT][BACK_CENTER] = aluSqrt(0.5); + Device->ChannelMatrix[BACK_LEFT][SIDE_LEFT] = aluSqrt(0.5); + Device->ChannelMatrix[BACK_RIGHT][BACK_CENTER] = aluSqrt(0.5); + Device->ChannelMatrix[BACK_RIGHT][SIDE_RIGHT] = aluSqrt(0.5); + Device->NumChan = 6; + Speaker2Chan[0] = SIDE_LEFT; + Speaker2Chan[1] = FRONT_LEFT; + Speaker2Chan[2] = FRONT_CENTER; + Speaker2Chan[3] = FRONT_RIGHT; + Speaker2Chan[4] = SIDE_RIGHT; + Speaker2Chan[5] = BACK_CENTER; + SpeakerAngle[0] = -90.0f * M_PI/180.0f; + SpeakerAngle[1] = -30.0f * M_PI/180.0f; + SpeakerAngle[2] = 0.0f * M_PI/180.0f; + SpeakerAngle[3] = 30.0f * M_PI/180.0f; + SpeakerAngle[4] = 90.0f * M_PI/180.0f; + SpeakerAngle[5] = 180.0f * M_PI/180.0f; + SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan); + break; + + case AL_FORMAT_71CHN8: + case AL_FORMAT_71CHN16: + case AL_FORMAT_71CHN32: + Device->DuplicateStereo = GetConfigValueBool(NULL, "stereodup", 0); + Device->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5); + Device->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5); + Device->NumChan = 7; + Speaker2Chan[0] = BACK_LEFT; + Speaker2Chan[1] = SIDE_LEFT; + Speaker2Chan[2] = FRONT_LEFT; + Speaker2Chan[3] = FRONT_CENTER; + Speaker2Chan[4] = FRONT_RIGHT; + Speaker2Chan[5] = SIDE_RIGHT; + Speaker2Chan[6] = BACK_RIGHT; + SpeakerAngle[0] = -150.0f * M_PI/180.0f; + SpeakerAngle[1] = -90.0f * M_PI/180.0f; + SpeakerAngle[2] = -30.0f * M_PI/180.0f; + SpeakerAngle[3] = 0.0f * M_PI/180.0f; + SpeakerAngle[4] = 30.0f * M_PI/180.0f; + SpeakerAngle[5] = 90.0f * M_PI/180.0f; + SpeakerAngle[6] = 150.0f * M_PI/180.0f; + SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan); + break; + + default: + assert(0); + } + + if(GetConfigValueBool(NULL, "scalemix", 0)) + { + ALfloat maxout = 1.0f; + for(s = 0;s < OUTPUTCHANNELS;s++) + { + ALfloat out = 0.0f; + for(s2 = 0;s2 < OUTPUTCHANNELS;s2++) + out += Device->ChannelMatrix[s2][s]; + maxout = __max(maxout, out); + } + + maxout = 1.0f/maxout; + for(s = 0;s < OUTPUTCHANNELS;s++) + { + for(s2 = 0;s2 < OUTPUTCHANNELS;s2++) + Device->ChannelMatrix[s2][s] *= maxout; + } + } + + for(pos = 0; pos < LUT_NUM; pos++) + { + /* clear all values */ + offset = OUTPUTCHANNELS * pos; + for(s = 0; s < OUTPUTCHANNELS; s++) + Device->PanningLUT[offset+s] = 0.0f; + + if(Device->NumChan == 1) + { + Device->PanningLUT[offset + Speaker2Chan[0]] = 1.0f; + continue; + } + + /* source angle */ + Theta = aluLUTpos2Angle(pos); + + /* set panning values */ + for(s = 0; s < Device->NumChan - 1; s++) + { + if(Theta >= SpeakerAngle[s] && Theta < SpeakerAngle[s+1]) + { + /* source between speaker s and speaker s+1 */ + Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) / + (SpeakerAngle[s+1]-SpeakerAngle[s]); + Device->PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha); + Device->PanningLUT[offset + Speaker2Chan[s+1]] = sin(Alpha); + break; + } + } + if(s == Device->NumChan - 1) + { + /* source between last and first speaker */ + if(Theta < SpeakerAngle[0]) + Theta += 2.0f * M_PI; + Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) / + (2.0f * M_PI + SpeakerAngle[0]-SpeakerAngle[s]); + Device->PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha); + Device->PanningLUT[offset + Speaker2Chan[0]] = sin(Alpha); + } + } +} + +static ALvoid CalcNonAttnSourceParams(const ALCcontext *ALContext, ALsource *ALSource) +{ + ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume; + ALfloat DryGain, DryGainHF; + ALfloat WetGain[MAX_SENDS]; + ALfloat WetGainHF[MAX_SENDS]; + ALint NumSends, Frequency; + ALfloat cw; + ALint i; + + //Get context properties + NumSends = ALContext->Device->NumAuxSends; + Frequency = ALContext->Device->Frequency; + + //Get listener properties + ListenerGain = ALContext->Listener.Gain; + + //Get source properties + SourceVolume = ALSource->flGain; + MinVolume = ALSource->flMinGain; + MaxVolume = ALSource->flMaxGain; + + //1. Multi-channel buffers always play "normal" + ALSource->Params.Pitch = ALSource->flPitch; + + DryGain = SourceVolume; + DryGain = __min(DryGain,MaxVolume); + DryGain = __max(DryGain,MinVolume); + DryGainHF = 1.0f; + + switch(ALSource->DirectFilter.type) + { + case AL_FILTER_LOWPASS: + DryGain *= ALSource->DirectFilter.Gain; + DryGainHF *= ALSource->DirectFilter.GainHF; + break; + } + + for(i = 0;i < OUTPUTCHANNELS;i++) + ALSource->Params.DryGains[i] = DryGain * ListenerGain; + + for(i = 0;i < NumSends;i++) + { + WetGain[i] = SourceVolume; + WetGain[i] = __min(WetGain[i],MaxVolume); + WetGain[i] = __max(WetGain[i],MinVolume); + WetGainHF[i] = 1.0f; + + switch(ALSource->Send[i].WetFilter.type) + { + case AL_FILTER_LOWPASS: + WetGain[i] *= ALSource->Send[i].WetFilter.Gain; + WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF; + break; + } + + ALSource->Params.WetGains[i] = WetGain[i] * ListenerGain; + } + for(i = NumSends;i < MAX_SENDS;i++) + { + ALSource->Params.WetGains[i] = 0.0f; + WetGainHF[i] = 1.0f; + } + + /* Update filter coefficients. Calculations based on the I3DL2 + * spec. */ + cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency); + + /* We use two chained one-pole filters, so we need to take the + * square root of the squared gain, which is the same as the base + * gain. */ + ALSource->Params.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw); + + for(i = 0;i < NumSends;i++) + { + /* We use a one-pole filter, so we need to take the squared gain */ + ALfloat a = lpCoeffCalc(WetGainHF[i]*WetGainHF[i], cw); + ALSource->Params.Send[i].iirFilter.coeff = a; + } +} + +static ALvoid CalcSourceParams(const ALCcontext *ALContext, ALsource *ALSource) +{ + const ALCdevice *Device = ALContext->Device; + ALfloat InnerAngle,OuterAngle,Angle,Distance,DryMix,OrigDist; + ALfloat Direction[3],Position[3],SourceToListener[3]; + ALfloat Velocity[3],ListenerVel[3]; + ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff,OuterGainHF; + ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain; + ALfloat DopplerFactor, DopplerVelocity, flSpeedOfSound; + ALfloat Matrix[4][4]; + ALfloat flAttenuation, effectiveDist; + ALfloat RoomAttenuation[MAX_SENDS]; + ALfloat MetersPerUnit; + ALfloat RoomRolloff[MAX_SENDS]; + ALfloat DryGainHF = 1.0f; + ALfloat WetGain[MAX_SENDS]; + ALfloat WetGainHF[MAX_SENDS]; + ALfloat DirGain, AmbientGain; + const ALfloat *SpeakerGain; + ALfloat length; + ALuint Frequency; + ALint NumSends; + ALint pos, s, i; + ALfloat cw; + + for(i = 0;i < MAX_SENDS;i++) + WetGainHF[i] = 1.0f; + + //Get context properties + DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor; + DopplerVelocity = ALContext->DopplerVelocity; + flSpeedOfSound = ALContext->flSpeedOfSound; + NumSends = Device->NumAuxSends; + Frequency = Device->Frequency; + + //Get listener properties + ListenerGain = ALContext->Listener.Gain; + MetersPerUnit = ALContext->Listener.MetersPerUnit; + memcpy(ListenerVel, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity)); + + //Get source properties + SourceVolume = ALSource->flGain; + memcpy(Position, ALSource->vPosition, sizeof(ALSource->vPosition)); + memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation)); + memcpy(Velocity, ALSource->vVelocity, sizeof(ALSource->vVelocity)); + MinVolume = ALSource->flMinGain; + MaxVolume = ALSource->flMaxGain; + MinDist = ALSource->flRefDistance; + MaxDist = ALSource->flMaxDistance; + Rolloff = ALSource->flRollOffFactor; + InnerAngle = ALSource->flInnerAngle; + OuterAngle = ALSource->flOuterAngle; + OuterGainHF = ALSource->OuterGainHF; + + //1. Translate Listener to origin (convert to head relative) + if(ALSource->bHeadRelative==AL_FALSE) + { + ALfloat U[3],V[3],N[3]; + + // Build transform matrix + memcpy(N, ALContext->Listener.Forward, sizeof(N)); // At-vector + aluNormalize(N); // Normalized At-vector + memcpy(V, ALContext->Listener.Up, sizeof(V)); // Up-vector + aluNormalize(V); // Normalized Up-vector + aluCrossproduct(N, V, U); // Right-vector + aluNormalize(U); // Normalized Right-vector + Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0]; Matrix[0][3] = 0.0f; + Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1]; Matrix[1][3] = 0.0f; + Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; Matrix[2][3] = 0.0f; + Matrix[3][0] = 0.0f; Matrix[3][1] = 0.0f; Matrix[3][2] = 0.0f; Matrix[3][3] = 1.0f; + + // Translate position + Position[0] -= ALContext->Listener.Position[0]; + Position[1] -= ALContext->Listener.Position[1]; + Position[2] -= ALContext->Listener.Position[2]; + + // Transform source position and direction into listener space + aluMatrixVector(Position, 1.0f, Matrix); + aluMatrixVector(Direction, 0.0f, Matrix); + // Transform source and listener velocity into listener space + aluMatrixVector(Velocity, 0.0f, Matrix); + aluMatrixVector(ListenerVel, 0.0f, Matrix); + } + else + ListenerVel[0] = ListenerVel[1] = ListenerVel[2] = 0.0f; + + SourceToListener[0] = -Position[0]; + SourceToListener[1] = -Position[1]; + SourceToListener[2] = -Position[2]; + aluNormalize(SourceToListener); + aluNormalize(Direction); + + //2. Calculate distance attenuation + Distance = aluSqrt(aluDotproduct(Position, Position)); + OrigDist = Distance; + + flAttenuation = 1.0f; + for(i = 0;i < NumSends;i++) + { + RoomAttenuation[i] = 1.0f; + + RoomRolloff[i] = ALSource->RoomRolloffFactor; + if(ALSource->Send[i].Slot && + (ALSource->Send[i].Slot->effect.type == AL_EFFECT_REVERB || + ALSource->Send[i].Slot->effect.type == AL_EFFECT_EAXREVERB)) + RoomRolloff[i] += ALSource->Send[i].Slot->effect.Reverb.RoomRolloffFactor; + } + + switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel : + ALContext->DistanceModel) + { + case AL_INVERSE_DISTANCE_CLAMPED: + Distance=__max(Distance,MinDist); + Distance=__min(Distance,MaxDist); + if(MaxDist < MinDist) + break; + //fall-through + case AL_INVERSE_DISTANCE: + if(MinDist > 0.0f) + { + if((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f) + flAttenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist))); + for(i = 0;i < NumSends;i++) + { + if((MinDist + (RoomRolloff[i] * (Distance - MinDist))) > 0.0f) + RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (Distance - MinDist))); + } + } + break; + + case AL_LINEAR_DISTANCE_CLAMPED: + Distance=__max(Distance,MinDist); + Distance=__min(Distance,MaxDist); + if(MaxDist < MinDist) + break; + //fall-through + case AL_LINEAR_DISTANCE: + Distance=__min(Distance,MaxDist); + if(MaxDist != MinDist) + { + flAttenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist)); + for(i = 0;i < NumSends;i++) + RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(Distance-MinDist)/(MaxDist - MinDist)); + } + break; + + case AL_EXPONENT_DISTANCE_CLAMPED: + Distance=__max(Distance,MinDist); + Distance=__min(Distance,MaxDist); + if(MaxDist < MinDist) + break; + //fall-through + case AL_EXPONENT_DISTANCE: + if(Distance > 0.0f && MinDist > 0.0f) + { + flAttenuation = aluPow(Distance/MinDist, -Rolloff); + for(i = 0;i < NumSends;i++) + RoomAttenuation[i] = aluPow(Distance/MinDist, -RoomRolloff[i]); + } + break; + + case AL_NONE: + break; + } + + // Source Gain + Attenuation + DryMix = SourceVolume * flAttenuation; + for(i = 0;i < NumSends;i++) + WetGain[i] = SourceVolume * RoomAttenuation[i]; + + effectiveDist = 0.0f; + if(MinDist > 0.0f) + effectiveDist = (MinDist/flAttenuation - MinDist)*MetersPerUnit; + + // Distance-based air absorption + if(ALSource->AirAbsorptionFactor > 0.0f && effectiveDist > 0.0f) + { + ALfloat absorb; + + // Absorption calculation is done in dB + absorb = (ALSource->AirAbsorptionFactor*AIRABSORBGAINDBHF) * + effectiveDist; + // Convert dB to linear gain before applying + absorb = aluPow(10.0f, absorb/20.0f); + + DryGainHF *= absorb; + } + + //3. Apply directional soundcones + Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * 180.0f/M_PI; + if(Angle >= InnerAngle && Angle <= OuterAngle) + { + ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle); + ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f)*scale); + ConeHF = (1.0f+(OuterGainHF-1.0f)*scale); + } + else if(Angle > OuterAngle) + { + ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f)); + ConeHF = (1.0f+(OuterGainHF-1.0f)); + } + else + { + ConeVolume = 1.0f; + ConeHF = 1.0f; + } + + // Apply some high-frequency attenuation for sources behind the listener + // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however + // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is + // the same as SourceToListener[2] + Angle = aluAcos(SourceToListener[2]) * 180.0f/M_PI; + // Sources within the minimum distance attenuate less + if(OrigDist < MinDist) + Angle *= OrigDist/MinDist; + if(Angle > 90.0f) + { + ALfloat scale = (Angle-90.0f) / (180.1f-90.0f); // .1 to account for fp errors + ConeHF *= 1.0f - (Device->HeadDampen*scale); + } + + DryMix *= ConeVolume; + if(ALSource->DryGainHFAuto) + DryGainHF *= ConeHF; + + // Clamp to Min/Max Gain + DryMix = __min(DryMix,MaxVolume); + DryMix = __max(DryMix,MinVolume); + + for(i = 0;i < NumSends;i++) + { + ALeffectslot *Slot = ALSource->Send[i].Slot; + + if(!Slot || Slot->effect.type == AL_EFFECT_NULL) + { + ALSource->Params.WetGains[i] = 0.0f; + WetGainHF[i] = 1.0f; + continue; + } + + if(Slot->AuxSendAuto) + { + if(ALSource->WetGainAuto) + WetGain[i] *= ConeVolume; + if(ALSource->WetGainHFAuto) + WetGainHF[i] *= ConeHF; + + // Clamp to Min/Max Gain + WetGain[i] = __min(WetGain[i],MaxVolume); + WetGain[i] = __max(WetGain[i],MinVolume); + + if(Slot->effect.type == AL_EFFECT_REVERB || + Slot->effect.type == AL_EFFECT_EAXREVERB) + { + /* Apply a decay-time transformation to the wet path, based on + * the attenuation of the dry path. + * + * Using the approximate (effective) source to listener + * distance, the initial decay of the reverb effect is + * calculated and applied to the wet path. + */ + WetGain[i] *= aluPow(10.0f, effectiveDist / + (SPEEDOFSOUNDMETRESPERSEC * + Slot->effect.Reverb.DecayTime) * + -60.0 / 20.0); + + WetGainHF[i] *= aluPow(10.0f, + log10(Slot->effect.Reverb.AirAbsorptionGainHF) * + ALSource->AirAbsorptionFactor * effectiveDist); + } + } + else + { + /* If the slot's auxiliary send auto is off, the data sent to the + * effect slot is the same as the dry path, sans filter effects */ + WetGain[i] = DryMix; + WetGainHF[i] = DryGainHF; + } + + switch(ALSource->Send[i].WetFilter.type) + { + case AL_FILTER_LOWPASS: + WetGain[i] *= ALSource->Send[i].WetFilter.Gain; + WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF; + break; + } + ALSource->Params.WetGains[i] = WetGain[i] * ListenerGain; + } + for(i = NumSends;i < MAX_SENDS;i++) + { + ALSource->Params.WetGains[i] = 0.0f; + WetGainHF[i] = 1.0f; + } + + // Apply filter gains and filters + switch(ALSource->DirectFilter.type) + { + case AL_FILTER_LOWPASS: + DryMix *= ALSource->DirectFilter.Gain; + DryGainHF *= ALSource->DirectFilter.GainHF; + break; + } + DryMix *= ListenerGain; + + // Calculate Velocity + if(DopplerFactor != 0.0f) + { + ALfloat flVSS, flVLS; + ALfloat flMaxVelocity = (DopplerVelocity * flSpeedOfSound) / + DopplerFactor; + + flVSS = aluDotproduct(Velocity, SourceToListener); + if(flVSS >= flMaxVelocity) + flVSS = (flMaxVelocity - 1.0f); + else if(flVSS <= -flMaxVelocity) + flVSS = -flMaxVelocity + 1.0f; + + flVLS = aluDotproduct(ListenerVel, SourceToListener); + if(flVLS >= flMaxVelocity) + flVLS = (flMaxVelocity - 1.0f); + else if(flVLS <= -flMaxVelocity) + flVLS = -flMaxVelocity + 1.0f; + + ALSource->Params.Pitch = ALSource->flPitch * + ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVLS)) / + ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVSS)); + } + else + ALSource->Params.Pitch = ALSource->flPitch; + + // Use energy-preserving panning algorithm for multi-speaker playback + length = __max(OrigDist, MinDist); + if(length > 0.0f) + { + ALfloat invlen = 1.0f/length; + Position[0] *= invlen; + Position[1] *= invlen; + Position[2] *= invlen; + } + + pos = aluCart2LUTpos(-Position[2], Position[0]); + SpeakerGain = &Device->PanningLUT[OUTPUTCHANNELS * pos]; + + DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]); + // elevation adjustment for directional gain. this sucks, but + // has low complexity + AmbientGain = 1.0/aluSqrt(Device->NumChan) * (1.0-DirGain); + for(s = 0;s < OUTPUTCHANNELS;s++) + ALSource->Params.DryGains[s] = 0.0f; + for(s = 0;s < (ALsizei)Device->NumChan;s++) + { + Channel chan = Device->Speaker2Chan[s]; + ALfloat gain = SpeakerGain[chan]*DirGain + AmbientGain; + ALSource->Params.DryGains[chan] = DryMix * gain; + } + + /* Update filter coefficients. */ + cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency); + + /* Spatialized sources use four chained one-pole filters, so we need to + * take the fourth root of the squared gain, which is the same as the + * square root of the base gain. */ + ALSource->Params.iirFilter.coeff = lpCoeffCalc(aluSqrt(DryGainHF), cw); + + for(i = 0;i < NumSends;i++) + { + /* The wet path uses two chained one-pole filters, so take the + * base gain (square root of the squared gain) */ + ALSource->Params.Send[i].iirFilter.coeff = lpCoeffCalc(WetGainHF[i], cw); + } +} + +static __inline ALfloat point(ALfloat val1, ALfloat val2, ALint frac) +{ + return val1; + (void)val2; + (void)frac; +} +static __inline ALfloat lerp(ALfloat val1, ALfloat val2, ALint frac) +{ + return val1 + ((val2-val1)*(frac * (1.0f/(1<Device->DuplicateStereo; + DeviceFreq = ALContext->Device->Frequency; + + rampLength = DeviceFreq * MIN_RAMP_LENGTH / 1000; + rampLength = max(rampLength, SamplesToDo); + + pos = 0; +next_source: + while(ALContext->ActiveSourceCount > pos) + { + ALsizei end; + + ALSource = ALContext->ActiveSources[pos]; + if(ALSource->state == AL_PLAYING) + break; + + end = --(ALContext->ActiveSourceCount); + ALContext->ActiveSources[pos] = ALContext->ActiveSources[end]; + } + if(pos >= ALContext->ActiveSourceCount) + return; + + /* Find buffer format */ + Frequency = 0; + Channels = 0; + Bytes = 0; + BufferListItem = ALSource->queue; + while(BufferListItem != NULL) + { + ALbuffer *ALBuffer; + if((ALBuffer=BufferListItem->buffer) != NULL) + { + Channels = aluChannelsFromFormat(ALBuffer->format); + Bytes = aluBytesFromFormat(ALBuffer->format); + Frequency = ALBuffer->frequency; + break; + } + BufferListItem = BufferListItem->next; + } + + if(ALSource->NeedsUpdate) + { + //Only apply 3D calculations for mono buffers + if(Channels == 1) + CalcSourceParams(ALContext, ALSource); + else + CalcNonAttnSourceParams(ALContext, ALSource); + ALSource->NeedsUpdate = AL_FALSE; + } + + /* Get source info */ + Resampler = ALSource->Resampler; + State = ALSource->state; + BuffersPlayed = ALSource->BuffersPlayed; + DataPosInt = ALSource->position; + DataPosFrac = ALSource->position_fraction; + Looping = ALSource->bLooping; + + /* Compute 18.14 fixed point step */ + Pitch = (ALSource->Params.Pitch*Frequency) / DeviceFreq; + if(Pitch > (float)MAX_PITCH) Pitch = (float)MAX_PITCH; + increment = (ALint)(Pitch*(ALfloat)(1L<FirstStart) + { + for(i = 0;i < OUTPUTCHANNELS;i++) + DrySend[i] = ALSource->Params.DryGains[i]; + for(i = 0;i < MAX_SENDS;i++) + WetSend[i] = ALSource->Params.WetGains[i]; + } + else + { + for(i = 0;i < OUTPUTCHANNELS;i++) + DrySend[i] = ALSource->DryGains[i]; + for(i = 0;i < MAX_SENDS;i++) + WetSend[i] = ALSource->WetGains[i]; + } + + DryFilter = &ALSource->Params.iirFilter; + for(i = 0;i < MAX_SENDS;i++) + { + WetFilter[i] = &ALSource->Params.Send[i].iirFilter; + WetBuffer[i] = (ALSource->Send[i].Slot ? + ALSource->Send[i].Slot->WetBuffer : + DummyBuffer); + } + + /* Get current buffer queue item */ + BufferListItem = ALSource->queue; + for(i = 0;i < BuffersPlayed && BufferListItem;i++) + BufferListItem = BufferListItem->next; + + j = 0; + do { + ALfloat *Data = NULL; + ALuint LoopStart = 0; + ALuint LoopEnd = 0; + ALuint DataSize = 0; + ALbuffer *ALBuffer; + ALuint BufferSize; + + /* Get buffer info */ + if((ALBuffer=BufferListItem->buffer) != NULL) + { + Data = ALBuffer->data; + DataSize = ALBuffer->size; + DataSize /= Channels * Bytes; + LoopStart = ALBuffer->LoopStart; + LoopEnd = ALBuffer->LoopEnd; + } + + if(Looping && ALSource->lSourceType == AL_STATIC) + { + /* If current offset is beyond the loop range, do not loop */ + if(DataPosInt >= LoopEnd) + Looping = AL_FALSE; + } + if(!Looping || ALSource->lSourceType != AL_STATIC) + { + /* Non-looping and non-static sources ignore loop points */ + LoopStart = 0; + LoopEnd = DataSize; + } + + if(DataPosInt >= DataSize) + goto skipmix; + + if(BufferListItem->next) + { + ALbuffer *NextBuf = BufferListItem->next->buffer; + if(NextBuf && NextBuf->size) + { + ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes; + ulExtraSamples = min(NextBuf->size, ulExtraSamples); + memcpy(&Data[DataSize*Channels], NextBuf->data, ulExtraSamples); + } + } + else if(Looping) + { + ALbuffer *NextBuf = ALSource->queue->buffer; + if(NextBuf && NextBuf->size) + { + ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes; + ulExtraSamples = min(NextBuf->size, ulExtraSamples); + memcpy(&Data[DataSize*Channels], &NextBuf->data[LoopStart*Channels], ulExtraSamples); + } + } + else + memset(&Data[DataSize*Channels], 0, (BUFFER_PADDING*Channels*Bytes)); + + /* Compute the gain steps for each output channel */ + for(i = 0;i < OUTPUTCHANNELS;i++) + dryGainStep[i] = (ALSource->Params.DryGains[i]-DrySend[i]) / + rampLength; + for(i = 0;i < MAX_SENDS;i++) + wetGainStep[i] = (ALSource->Params.WetGains[i]-WetSend[i]) / + rampLength; + + /* Figure out how many samples we can mix. */ + DataSize64 = LoopEnd; + DataSize64 <<= FRACTIONBITS; + DataPos64 = DataPosInt; + DataPos64 <<= FRACTIONBITS; + DataPos64 += DataPosFrac; + BufferSize = (ALuint)((DataSize64-DataPos64+(increment-1)) / increment); + + BufferSize = min(BufferSize, (SamplesToDo-j)); + + /* Actual sample mixing loop */ + k = 0; + Data += DataPosInt*Channels; + + if(Channels == 1) /* Mono */ + { +#define DO_MIX(resampler) do { \ + while(BufferSize--) \ + { \ + for(i = 0;i < OUTPUTCHANNELS;i++) \ + DrySend[i] += dryGainStep[i]; \ + for(i = 0;i < MAX_SENDS;i++) \ + WetSend[i] += wetGainStep[i]; \ + \ + /* First order interpolator */ \ + value = (resampler)(Data[k], Data[k+1], DataPosFrac); \ + \ + /* Direct path final mix buffer and panning */ \ + outsamp = lpFilter4P(DryFilter, 0, value); \ + DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \ + DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \ + DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \ + DryBuffer[j][SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \ + DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \ + DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \ + DryBuffer[j][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \ + DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \ + \ + /* Room path final mix buffer and panning */ \ + for(i = 0;i < MAX_SENDS;i++) \ + { \ + outsamp = lpFilter2P(WetFilter[i], 0, value); \ + WetBuffer[i][j] += outsamp*WetSend[i]; \ + } \ + \ + DataPosFrac += increment; \ + k += DataPosFrac>>FRACTIONBITS; \ + DataPosFrac &= FRACTIONMASK; \ + j++; \ + } \ +} while(0) + + switch(Resampler) + { + case POINT_RESAMPLER: + DO_MIX(point); break; + case LINEAR_RESAMPLER: + DO_MIX(lerp); break; + case COSINE_RESAMPLER: + DO_MIX(cos_lerp); break; + case RESAMPLER_MIN: + case RESAMPLER_MAX: + break; + } +#undef DO_MIX + } + else if(Channels == 2 && DuplicateStereo) /* Stereo */ + { + const int chans[] = { + FRONT_LEFT, FRONT_RIGHT + }; + const int chans2[] = { + BACK_LEFT, SIDE_LEFT, BACK_RIGHT, SIDE_RIGHT + }; + const ALfloat scaler = 1.0f/Channels; + const ALfloat dupscaler = aluSqrt(1.0f/3.0f); + +#define DO_MIX(resampler) do { \ + while(BufferSize--) \ + { \ + for(i = 0;i < OUTPUTCHANNELS;i++) \ + DrySend[i] += dryGainStep[i]; \ + for(i = 0;i < MAX_SENDS;i++) \ + WetSend[i] += wetGainStep[i]; \ + \ + for(i = 0;i < Channels;i++) \ + { \ + value = (resampler)(Data[k*Channels + i],Data[(k+1)*Channels + i],\ + DataPosFrac); \ + outsamp = lpFilter2P(DryFilter, chans[i]*2, value) * dupscaler; \ + DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \ + DryBuffer[j][chans2[i*2+0]] += outsamp*DrySend[chans2[i*2+0]]; \ + DryBuffer[j][chans2[i*2+1]] += outsamp*DrySend[chans2[i*2+1]]; \ + for(out = 0;out < MAX_SENDS;out++) \ + { \ + outsamp = lpFilter1P(WetFilter[out], chans[i], value); \ + WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \ + } \ + } \ + \ + DataPosFrac += increment; \ + k += DataPosFrac>>FRACTIONBITS; \ + DataPosFrac &= FRACTIONMASK; \ + j++; \ + } \ +} while(0) + + switch(Resampler) + { + case POINT_RESAMPLER: + DO_MIX(point); break; + case LINEAR_RESAMPLER: + DO_MIX(lerp); break; + case COSINE_RESAMPLER: + DO_MIX(cos_lerp); break; + case RESAMPLER_MIN: + case RESAMPLER_MAX: + break; + } +#undef DO_MIX + } + else if(Channels == 2) /* Stereo */ + { + const int chans[] = { + FRONT_LEFT, FRONT_RIGHT + }; + const ALfloat scaler = 1.0f/Channels; + +#define DO_MIX(resampler) do { \ + while(BufferSize--) \ + { \ + for(i = 0;i < OUTPUTCHANNELS;i++) \ + DrySend[i] += dryGainStep[i]; \ + for(i = 0;i < MAX_SENDS;i++) \ + WetSend[i] += wetGainStep[i]; \ + \ + for(i = 0;i < Channels;i++) \ + { \ + value = (resampler)(Data[k*Channels + i],Data[(k+1)*Channels + i],\ + DataPosFrac); \ + outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \ + DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \ + for(out = 0;out < MAX_SENDS;out++) \ + { \ + outsamp = lpFilter1P(WetFilter[out], chans[i], value); \ + WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \ + } \ + } \ + \ + DataPosFrac += increment; \ + k += DataPosFrac>>FRACTIONBITS; \ + DataPosFrac &= FRACTIONMASK; \ + j++; \ + } \ +} while(0) + + switch(Resampler) + { + case POINT_RESAMPLER: + DO_MIX(point); break; + case LINEAR_RESAMPLER: + DO_MIX(lerp); break; + case COSINE_RESAMPLER: + DO_MIX(cos_lerp); break; + case RESAMPLER_MIN: + case RESAMPLER_MAX: + break; + } + } + else if(Channels == 4) /* Quad */ + { + const int chans[] = { + FRONT_LEFT, FRONT_RIGHT, + BACK_LEFT, BACK_RIGHT + }; + const ALfloat scaler = 1.0f/Channels; + + switch(Resampler) + { + case POINT_RESAMPLER: + DO_MIX(point); break; + case LINEAR_RESAMPLER: + DO_MIX(lerp); break; + case COSINE_RESAMPLER: + DO_MIX(cos_lerp); break; + case RESAMPLER_MIN: + case RESAMPLER_MAX: + break; + } + } + else if(Channels == 6) /* 5.1 */ + { + const int chans[] = { + FRONT_LEFT, FRONT_RIGHT, + FRONT_CENTER, LFE, + BACK_LEFT, BACK_RIGHT + }; + const ALfloat scaler = 1.0f/Channels; + + switch(Resampler) + { + case POINT_RESAMPLER: + DO_MIX(point); break; + case LINEAR_RESAMPLER: + DO_MIX(lerp); break; + case COSINE_RESAMPLER: + DO_MIX(cos_lerp); break; + case RESAMPLER_MIN: + case RESAMPLER_MAX: + break; + } + } + else if(Channels == 7) /* 6.1 */ + { + const int chans[] = { + FRONT_LEFT, FRONT_RIGHT, + FRONT_CENTER, LFE, + BACK_CENTER, + SIDE_LEFT, SIDE_RIGHT + }; + const ALfloat scaler = 1.0f/Channels; + + switch(Resampler) + { + case POINT_RESAMPLER: + DO_MIX(point); break; + case LINEAR_RESAMPLER: + DO_MIX(lerp); break; + case COSINE_RESAMPLER: + DO_MIX(cos_lerp); break; + case RESAMPLER_MIN: + case RESAMPLER_MAX: + break; + } + } + else if(Channels == 8) /* 7.1 */ + { + const int chans[] = { + FRONT_LEFT, FRONT_RIGHT, + FRONT_CENTER, LFE, + BACK_LEFT, BACK_RIGHT, + SIDE_LEFT, SIDE_RIGHT + }; + const ALfloat scaler = 1.0f/Channels; + + switch(Resampler) + { + case POINT_RESAMPLER: + DO_MIX(point); break; + case LINEAR_RESAMPLER: + DO_MIX(lerp); break; + case COSINE_RESAMPLER: + DO_MIX(cos_lerp); break; + case RESAMPLER_MIN: + case RESAMPLER_MAX: + break; + } +#undef DO_MIX + } + else /* Unknown? */ + { + for(i = 0;i < OUTPUTCHANNELS;i++) + DrySend[i] += dryGainStep[i]*BufferSize; + for(i = 0;i < MAX_SENDS;i++) + WetSend[i] += wetGainStep[i]*BufferSize; + while(BufferSize--) + { + DataPosFrac += increment; + k += DataPosFrac>>FRACTIONBITS; + DataPosFrac &= FRACTIONMASK; + j++; + } + } + DataPosInt += k; + + skipmix: + /* Handle looping sources */ + if(DataPosInt >= LoopEnd) + { + if(BuffersPlayed < (ALSource->BuffersInQueue-1)) + { + BufferListItem = BufferListItem->next; + BuffersPlayed++; + DataPosInt -= DataSize; + } + else if(Looping) + { + BufferListItem = ALSource->queue; + BuffersPlayed = 0; + if(ALSource->lSourceType == AL_STATIC) + DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; + else + DataPosInt -= DataSize; + } + else + { + State = AL_STOPPED; + BufferListItem = ALSource->queue; + BuffersPlayed = ALSource->BuffersInQueue; + DataPosInt = 0; + DataPosFrac = 0; + } + } + } while(State == AL_PLAYING && j < SamplesToDo); + + /* Update source info */ + ALSource->state = State; + ALSource->BuffersPlayed = BuffersPlayed; + ALSource->position = DataPosInt; + ALSource->position_fraction = DataPosFrac; + ALSource->Buffer = BufferListItem->buffer; + + for(i = 0;i < OUTPUTCHANNELS;i++) + ALSource->DryGains[i] = DrySend[i]; + for(i = 0;i < MAX_SENDS;i++) + ALSource->WetGains[i] = WetSend[i]; + + ALSource->FirstStart = AL_FALSE; + + if(ALSource->state == AL_PLAYING) + pos++; + goto next_source; +} + +ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) +{ + float (*DryBuffer)[OUTPUTCHANNELS]; + ALfloat (*Matrix)[OUTPUTCHANNELS]; + const ALuint *ChanMap; + ALuint SamplesToDo; + ALeffectslot *ALEffectSlot; + ALCcontext *ALContext; + ALfloat samp; + int fpuState; + ALuint i, j, c; + ALsizei e; + +#if defined(HAVE_FESETROUND) + fpuState = fegetround(); + fesetround(FE_TOWARDZERO); +#elif defined(HAVE__CONTROLFP) + fpuState = _controlfp(0, 0); + _controlfp(_RC_CHOP, _MCW_RC); +#else + (void)fpuState; +#endif + + DryBuffer = device->DryBuffer; + while(size > 0) + { + /* Setup variables */ + SamplesToDo = min(size, BUFFERSIZE); + + /* Clear mixing buffer */ + memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat)); + + SuspendContext(NULL); + for(c = 0;c < device->NumContexts;c++) + { + ALContext = device->Contexts[c]; + SuspendContext(ALContext); + + MixSomeSources(ALContext, DryBuffer, SamplesToDo); + + /* effect slot processing */ + for(e = 0;e < ALContext->EffectSlotMap.size;e++) + { + ALEffectSlot = ALContext->EffectSlotMap.array[e].value; + if(ALEffectSlot->EffectState) + ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer); + + for(i = 0;i < SamplesToDo;i++) + ALEffectSlot->WetBuffer[i] = 0.0f; + } + ProcessContext(ALContext); + } + ProcessContext(NULL); + + //Post processing loop + ChanMap = device->DevChannels; + Matrix = device->ChannelMatrix; + switch(device->Format) + { +#define CHECK_WRITE_FORMAT(bits, type, func) \ + case AL_FORMAT_MONO##bits: \ + for(i = 0;i < SamplesToDo;i++) \ + { \ + samp = 0.0f; \ + for(c = 0;c < OUTPUTCHANNELS;c++) \ + samp += DryBuffer[i][c] * Matrix[c][FRONT_CENTER]; \ + ((type*)buffer)[ChanMap[FRONT_CENTER]] = (func)(samp); \ + buffer = ((type*)buffer) + 1; \ + } \ + break; \ + case AL_FORMAT_STEREO##bits: \ + if(device->Bs2b) \ + { \ + for(i = 0;i < SamplesToDo;i++) \ + { \ + float samples[2] = { 0.0f, 0.0f }; \ + for(c = 0;c < OUTPUTCHANNELS;c++) \ + { \ + samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \ + samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \ + } \ + bs2b_cross_feed(device->Bs2b, samples); \ + ((type*)buffer)[ChanMap[FRONT_LEFT]] = (func)(samples[0]);\ + ((type*)buffer)[ChanMap[FRONT_RIGHT]]= (func)(samples[1]);\ + buffer = ((type*)buffer) + 2; \ + } \ + } \ + else \ + { \ + for(i = 0;i < SamplesToDo;i++) \ + { \ + static const Channel chans[] = { \ + FRONT_LEFT, FRONT_RIGHT \ + }; \ + for(j = 0;j < 2;j++) \ + { \ + samp = 0.0f; \ + for(c = 0;c < OUTPUTCHANNELS;c++) \ + samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \ + ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \ + } \ + buffer = ((type*)buffer) + 2; \ + } \ + } \ + break; \ + case AL_FORMAT_QUAD##bits: \ + for(i = 0;i < SamplesToDo;i++) \ + { \ + static const Channel chans[] = { \ + FRONT_LEFT, FRONT_RIGHT, \ + BACK_LEFT, BACK_RIGHT, \ + }; \ + for(j = 0;j < 4;j++) \ + { \ + samp = 0.0f; \ + for(c = 0;c < OUTPUTCHANNELS;c++) \ + samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \ + ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \ + } \ + buffer = ((type*)buffer) + 4; \ + } \ + break; \ + case AL_FORMAT_51CHN##bits: \ + for(i = 0;i < SamplesToDo;i++) \ + { \ + static const Channel chans[] = { \ + FRONT_LEFT, FRONT_RIGHT, \ + FRONT_CENTER, LFE, \ + BACK_LEFT, BACK_RIGHT, \ + }; \ + for(j = 0;j < 6;j++) \ + { \ + samp = 0.0f; \ + for(c = 0;c < OUTPUTCHANNELS;c++) \ + samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \ + ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \ + } \ + buffer = ((type*)buffer) + 6; \ + } \ + break; \ + case AL_FORMAT_61CHN##bits: \ + for(i = 0;i < SamplesToDo;i++) \ + { \ + static const Channel chans[] = { \ + FRONT_LEFT, FRONT_RIGHT, \ + FRONT_CENTER, LFE, BACK_CENTER, \ + SIDE_LEFT, SIDE_RIGHT, \ + }; \ + for(j = 0;j < 7;j++) \ + { \ + samp = 0.0f; \ + for(c = 0;c < OUTPUTCHANNELS;c++) \ + samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \ + ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \ + } \ + buffer = ((type*)buffer) + 7; \ + } \ + break; \ + case AL_FORMAT_71CHN##bits: \ + for(i = 0;i < SamplesToDo;i++) \ + { \ + static const Channel chans[] = { \ + FRONT_LEFT, FRONT_RIGHT, \ + FRONT_CENTER, LFE, \ + BACK_LEFT, BACK_RIGHT, \ + SIDE_LEFT, SIDE_RIGHT \ + }; \ + for(j = 0;j < 8;j++) \ + { \ + samp = 0.0f; \ + for(c = 0;c < OUTPUTCHANNELS;c++) \ + samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \ + ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \ + } \ + buffer = ((type*)buffer) + 8; \ + } \ + break; + +#define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32 +#define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32 + CHECK_WRITE_FORMAT(8, ALubyte, aluF2UB) + CHECK_WRITE_FORMAT(16, ALshort, aluF2S) + CHECK_WRITE_FORMAT(32, ALfloat, aluF2F) +#undef AL_FORMAT_STEREO32 +#undef AL_FORMAT_MONO32 +#undef CHECK_WRITE_FORMAT + + default: + break; + } + + size -= SamplesToDo; + } + +#if defined(HAVE_FESETROUND) + fesetround(fpuState); +#elif defined(HAVE__CONTROLFP) + _controlfp(fpuState, 0xfffff); +#endif +} + +ALvoid aluHandleDisconnect(ALCdevice *device) +{ + ALuint i; + + SuspendContext(NULL); + for(i = 0;i < device->NumContexts;i++) + { + ALCcontext *Context = device->Contexts[i]; + ALsource *source; + ALsizei pos; + + SuspendContext(Context); + + for(pos = 0;pos < Context->SourceMap.size;pos++) + { + source = Context->SourceMap.array[pos].value; + if(source->state == AL_PLAYING) + { + source->state = AL_STOPPED; + source->BuffersPlayed = source->BuffersInQueue; + source->position = 0; + source->position_fraction = 0; + } + } + ProcessContext(Context); + } + + device->Connected = ALC_FALSE; + ProcessContext(NULL); +} diff --git a/project/jni/openal/src/Alc/alcConfig.c b/project/jni/openal/src/Alc/alcConfig.c new file mode 100644 index 000000000..847e5d13f --- /dev/null +++ b/project/jni/openal/src/Alc/alcConfig.c @@ -0,0 +1,338 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#ifdef _WIN32 +#ifdef __MINGW64__ +#define _WIN32_IE 0x501 +#else +#define _WIN32_IE 0x400 +#endif +#endif + +#include "config.h" + +#include +#include +#include +#include + +#include "alMain.h" + +#ifdef _WIN32_IE +#include +#endif + +typedef struct ConfigEntry { + char *key; + char *value; +} ConfigEntry; + +typedef struct ConfigBlock { + char *name; + ConfigEntry *entries; + size_t entryCount; +} ConfigBlock; + +static ConfigBlock *cfgBlocks; +static size_t cfgCount; + +static char buffer[1024]; + +static void LoadConfigFromFile(FILE *f) +{ + ConfigBlock *curBlock = cfgBlocks; + ConfigEntry *ent; + + while(fgets(buffer, sizeof(buffer), f)) + { + size_t i = 0; + + while(isspace(buffer[i])) + i++; + if(!buffer[i] || buffer[i] == '#') + continue; + + memmove(buffer, buffer+i, strlen(buffer+i)+1); + + if(buffer[0] == '[') + { + ConfigBlock *nextBlock; + + i = 1; + while(buffer[i] && buffer[i] != ']') + i++; + + if(!buffer[i]) + { + AL_PRINT("config parse error: bad line \"%s\"\n", buffer); + continue; + } + buffer[i] = 0; + + do { + i++; + if(buffer[i] && !isspace(buffer[i])) + { + if(buffer[i] != '#') + AL_PRINT("config warning: extra data after block: \"%s\"\n", buffer+i); + break; + } + } while(buffer[i]); + + nextBlock = NULL; + for(i = 0;i < cfgCount;i++) + { + if(strcasecmp(cfgBlocks[i].name, buffer+1) == 0) + { + nextBlock = cfgBlocks+i; +// AL_PRINT("found block '%s'\n", nextBlock->name); + break; + } + } + + if(!nextBlock) + { + nextBlock = realloc(cfgBlocks, (cfgCount+1)*sizeof(ConfigBlock)); + if(!nextBlock) + { + AL_PRINT("config parse error: error reallocating config blocks\n"); + continue; + } + cfgBlocks = nextBlock; + nextBlock = cfgBlocks+cfgCount; + cfgCount++; + + nextBlock->name = strdup(buffer+1); + nextBlock->entries = NULL; + nextBlock->entryCount = 0; + +// AL_PRINT("found new block '%s'\n", nextBlock->name); + } + curBlock = nextBlock; + continue; + } + + /* Look for the option name */ + i = 0; + while(buffer[i] && buffer[i] != '#' && buffer[i] != '=' && + !isspace(buffer[i])) + i++; + + if(!buffer[i] || buffer[i] == '#' || i == 0) + { + AL_PRINT("config parse error: malformed option line: \"%s\"\n", buffer); + continue; + } + + /* Seperate the option */ + if(buffer[i] != '=') + { + buffer[i++] = 0; + + while(isspace(buffer[i])) + i++; + if(buffer[i] != '=') + { + AL_PRINT("config parse error: option without a value: \"%s\"\n", buffer); + continue; + } + } + /* Find the start of the value */ + buffer[i++] = 0; + while(isspace(buffer[i])) + i++; + + /* Check if we already have this option set */ + ent = curBlock->entries; + while((size_t)(ent-curBlock->entries) < curBlock->entryCount) + { + if(strcasecmp(ent->key, buffer) == 0) + break; + ent++; + } + + if((size_t)(ent-curBlock->entries) >= curBlock->entryCount) + { + /* Allocate a new option entry */ + ent = realloc(curBlock->entries, (curBlock->entryCount+1)*sizeof(ConfigEntry)); + if(!ent) + { + AL_PRINT("config parse error: error reallocating config entries\n"); + continue; + } + curBlock->entries = ent; + ent = curBlock->entries + curBlock->entryCount; + curBlock->entryCount++; + + ent->key = strdup(buffer); + ent->value = NULL; + } + + /* Look for the end of the line (Null term, new-line, or #-symbol) and + eat up the trailing whitespace */ + memmove(buffer, buffer+i, strlen(buffer+i)+1); + + i = 0; + while(buffer[i] && buffer[i] != '#' && buffer[i] != '\n') + i++; + do { + i--; + } while(isspace(buffer[i])); + buffer[++i] = 0; + + free(ent->value); + ent->value = strdup(buffer); + +// AL_PRINT("found '%s' = '%s'\n", ent->key, ent->value); + } +} + +void ReadALConfig(void) +{ + FILE *f; + + cfgBlocks = calloc(1, sizeof(ConfigBlock)); + cfgBlocks->name = strdup("general"); + cfgCount = 1; + +#ifdef _WIN32 + if(SHGetSpecialFolderPathA(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE) + { + size_t p = strlen(buffer); + snprintf(buffer+p, sizeof(buffer)-p, "\\alsoft.ini"); + f = fopen(buffer, "rt"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } +#else + f = fopen("/etc/openal/alsoft.conf", "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + if(getenv("HOME") && *(getenv("HOME"))) + { + snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", getenv("HOME")); + f = fopen(buffer, "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } +#endif + if(getenv("ALSOFT_CONF")) + { + f = fopen(getenv("ALSOFT_CONF"), "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } +} + +void FreeALConfig(void) +{ + size_t i; + + for(i = 0;i < cfgCount;i++) + { + size_t j; + for(j = 0;j < cfgBlocks[i].entryCount;j++) + { + free(cfgBlocks[i].entries[j].key); + free(cfgBlocks[i].entries[j].value); + } + free(cfgBlocks[i].entries); + free(cfgBlocks[i].name); + } + free(cfgBlocks); + cfgBlocks = NULL; + cfgCount = 0; +} + +const char *GetConfigValue(const char *blockName, const char *keyName, const char *def) +{ + size_t i, j; + + if(!keyName) + return def; + + if(!blockName) + blockName = "general"; + + for(i = 0;i < cfgCount;i++) + { + if(strcasecmp(cfgBlocks[i].name, blockName) != 0) + continue; + + for(j = 0;j < cfgBlocks[i].entryCount;j++) + { + if(strcasecmp(cfgBlocks[i].entries[j].key, keyName) == 0) + { + if(cfgBlocks[i].entries[j].value[0]) + return cfgBlocks[i].entries[j].value; + return def; + } + } + } + + return def; +} + +int ConfigValueExists(const char *blockName, const char *keyName) +{ + const char *val = GetConfigValue(blockName, keyName, ""); + return !!val[0]; +} + +int GetConfigValueInt(const char *blockName, const char *keyName, int def) +{ + const char *val = GetConfigValue(blockName, keyName, ""); + + if(!val[0]) return def; + return strtol(val, NULL, 0); +} + +float GetConfigValueFloat(const char *blockName, const char *keyName, float def) +{ + const char *val = GetConfigValue(blockName, keyName, ""); + + if(!val[0]) return def; +#ifdef HAVE_STRTOF + return strtof(val, NULL); +#else + return (float)strtod(val, NULL); +#endif +} + +int GetConfigValueBool(const char *blockName, const char *keyName, int def) +{ + const char *val = GetConfigValue(blockName, keyName, ""); + + if(!val[0]) return !!def; + return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || + strcasecmp(val, "on") == 0 || atoi(val) != 0); +} diff --git a/project/jni/openal/src/Alc/alcEcho.c b/project/jni/openal/src/Alc/alcEcho.c new file mode 100644 index 000000000..d6f7fbb3f --- /dev/null +++ b/project/jni/openal/src/Alc/alcEcho.c @@ -0,0 +1,193 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2009 by Chris Robinson. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + + +typedef struct ALechoState { + // Must be first in all effects! + ALeffectState state; + + ALfloat *SampleBuffer; + ALuint BufferLength; + + // The echo is two tap. The delay is the number of samples from before the + // current offset + struct { + ALuint delay; + } Tap[2]; + ALuint Offset; + // The LR gains for the first tap. The second tap uses the reverse + ALfloat GainL; + ALfloat GainR; + + ALfloat FeedGain; + + ALfloat Scale; + + FILTER iirFilter; + ALfloat history[2]; +} ALechoState; + +static ALvoid EchoDestroy(ALeffectState *effect) +{ + ALechoState *state = (ALechoState*)effect; + if(state) + { + free(state->SampleBuffer); + state->SampleBuffer = NULL; + free(state); + } +} + +static ALboolean EchoDeviceUpdate(ALeffectState *effect, ALCdevice *Device) +{ + ALechoState *state = (ALechoState*)effect; + ALuint maxlen, i; + + // Use the next power of 2 for the buffer length, so the tap offsets can be + // wrapped using a mask instead of a modulo + maxlen = (ALuint)(AL_ECHO_MAX_DELAY * Device->Frequency) + 1; + maxlen += (ALuint)(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1; + maxlen = NextPowerOf2(maxlen); + + if(maxlen != state->BufferLength) + { + void *temp; + + temp = realloc(state->SampleBuffer, maxlen * sizeof(ALfloat)); + if(!temp) + return AL_FALSE; + state->SampleBuffer = temp; + state->BufferLength = maxlen; + } + for(i = 0;i < state->BufferLength;i++) + state->SampleBuffer[i] = 0.0f; + + state->Scale = aluSqrt(Device->NumChan / 6.0f); + state->Scale = __min(state->Scale, 1.0f); + + return AL_TRUE; +} + +static ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect) +{ + ALechoState *state = (ALechoState*)effect; + ALuint frequency = Context->Device->Frequency; + ALfloat lrpan, cw, a, g; + + state->Tap[0].delay = (ALuint)(Effect->Echo.Delay * frequency) + 1; + state->Tap[1].delay = (ALuint)(Effect->Echo.LRDelay * frequency); + state->Tap[1].delay += state->Tap[0].delay; + + lrpan = Effect->Echo.Spread*0.5f + 0.5f; + state->GainL = aluSqrt( lrpan); + state->GainR = aluSqrt(1.0f-lrpan); + + state->FeedGain = Effect->Echo.Feedback; + + cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / frequency); + g = 1.0f - Effect->Echo.Damping; + a = 0.0f; + if(g < 0.9999f) // 1-epsilon + a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g); + state->iirFilter.coeff = a; +} + +static ALvoid EchoProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]) +{ + ALechoState *state = (ALechoState*)effect; + const ALuint mask = state->BufferLength-1; + const ALuint tap1 = state->Tap[0].delay; + const ALuint tap2 = state->Tap[1].delay; + ALuint offset = state->Offset; + const ALfloat gain = Slot->Gain * state->Scale; + ALfloat samp[2], smp; + ALuint i; + + for(i = 0;i < SamplesToDo;i++,offset++) + { + // Sample first tap + smp = state->SampleBuffer[(offset-tap1) & mask]; + samp[0] = smp * state->GainL; + samp[1] = smp * state->GainR; + // Sample second tap. Reverse LR panning + smp = state->SampleBuffer[(offset-tap2) & mask]; + samp[0] += smp * state->GainR; + samp[1] += smp * state->GainL; + + // Apply damping and feedback gain to the second tap, and mix in the + // new sample + smp = lpFilter2P(&state->iirFilter, 0, smp+SamplesIn[i]); + state->SampleBuffer[offset&mask] = smp * state->FeedGain; + + // Apply slot gain + samp[0] *= gain; + samp[1] *= gain; + + SamplesOut[i][FRONT_LEFT] += samp[0]; + SamplesOut[i][FRONT_RIGHT] += samp[1]; + SamplesOut[i][SIDE_LEFT] += samp[0]; + SamplesOut[i][SIDE_RIGHT] += samp[1]; + SamplesOut[i][BACK_LEFT] += samp[0]; + SamplesOut[i][BACK_RIGHT] += samp[1]; + } + state->Offset = offset; +} + +ALeffectState *EchoCreate(void) +{ + ALechoState *state; + + state = malloc(sizeof(*state)); + if(!state) + return NULL; + + state->state.Destroy = EchoDestroy; + state->state.DeviceUpdate = EchoDeviceUpdate; + state->state.Update = EchoUpdate; + state->state.Process = EchoProcess; + + state->BufferLength = 0; + state->SampleBuffer = NULL; + + state->Tap[0].delay = 0; + state->Tap[1].delay = 0; + state->Offset = 0; + state->GainL = 0.0f; + state->GainR = 0.0f; + + state->Scale = 1.0f; + + state->iirFilter.coeff = 0.0f; + state->iirFilter.history[0] = 0.0f; + state->iirFilter.history[1] = 0.0f; + + return &state->state; +} diff --git a/project/jni/openal/src/Alc/alcModulator.c b/project/jni/openal/src/Alc/alcModulator.c new file mode 100644 index 000000000..0578ee1c1 --- /dev/null +++ b/project/jni/openal/src/Alc/alcModulator.c @@ -0,0 +1,200 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2009 by Chris Robinson. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + + +typedef struct ALmodulatorState { + // Must be first in all effects! + ALeffectState state; + + enum { + SINUSOID, + SAWTOOTH, + SQUARE + } Waveform; + + ALuint index; + ALuint step; + + ALfloat Scale; + + FILTER iirFilter; + ALfloat history[1]; +} ALmodulatorState; + +#define WAVEFORM_FRACBITS 16 +#define WAVEFORM_FRACMASK ((1<>(WAVEFORM_FRACBITS-1))&1) ? -1.0f : 1.0f; +} + + +static __inline ALfloat hpFilter1P(FILTER *iir, ALuint offset, ALfloat input) +{ + ALfloat *history = &iir->history[offset]; + ALfloat a = iir->coeff; + ALfloat output = input; + + output = output + (history[0]-output)*a; + history[0] = output; + + return input - output; +} + + +static ALvoid ModulatorDestroy(ALeffectState *effect) +{ + ALmodulatorState *state = (ALmodulatorState*)effect; + free(state); +} + +static ALboolean ModulatorDeviceUpdate(ALeffectState *effect, ALCdevice *Device) +{ + ALmodulatorState *state = (ALmodulatorState*)effect; + + state->Scale = aluSqrt(Device->NumChan / 8.0f); + + return AL_TRUE; +} + +static ALvoid ModulatorUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect) +{ + ALmodulatorState *state = (ALmodulatorState*)effect; + ALfloat cw, a = 0.0f; + + if(Effect->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) + state->Waveform = SINUSOID; + else if(Effect->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) + state->Waveform = SAWTOOTH; + else if(Effect->Modulator.Waveform == AL_RING_MODULATOR_SQUARE) + state->Waveform = SQUARE; + + state->step = Effect->Modulator.Frequency*(1<Device->Frequency; + if(!state->step) + state->step = 1; + + cw = cos(2.0*M_PI * Effect->Modulator.HighPassCutoff / Context->Device->Frequency); + a = (2.0f-cw) - aluSqrt(aluPow(2.0f-cw, 2.0f) - 1.0f); + state->iirFilter.coeff = a; +} + +static ALvoid ModulatorProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]) +{ + ALmodulatorState *state = (ALmodulatorState*)effect; + const ALfloat gain = Slot->Gain * state->Scale; + const ALuint step = state->step; + ALuint index = state->index; + ALfloat samp; + ALuint i; + + switch(state->Waveform) + { + case SINUSOID: + for(i = 0;i < SamplesToDo;i++) + { +#define FILTER_OUT(func) do { \ + samp = SamplesIn[i]; \ + \ + index += step; \ + index &= WAVEFORM_FRACMASK; \ + samp *= func(index); \ + \ + samp = hpFilter1P(&state->iirFilter, 0, samp); \ + \ + /* Apply slot gain */ \ + samp *= gain; \ + \ + SamplesOut[i][FRONT_LEFT] += samp; \ + SamplesOut[i][FRONT_RIGHT] += samp; \ + SamplesOut[i][FRONT_CENTER] += samp; \ + SamplesOut[i][SIDE_LEFT] += samp; \ + SamplesOut[i][SIDE_RIGHT] += samp; \ + SamplesOut[i][BACK_LEFT] += samp; \ + SamplesOut[i][BACK_RIGHT] += samp; \ + SamplesOut[i][BACK_CENTER] += samp; \ +} while(0) + FILTER_OUT(sin_func); + } + break; + + case SAWTOOTH: + for(i = 0;i < SamplesToDo;i++) + { + FILTER_OUT(saw_func); + } + break; + + case SQUARE: + for(i = 0;i < SamplesToDo;i++) + { + FILTER_OUT(square_func); +#undef FILTER_OUT + } + break; + } + state->index = index; +} + +ALeffectState *ModulatorCreate(void) +{ + ALmodulatorState *state; + + state = malloc(sizeof(*state)); + if(!state) + return NULL; + + state->state.Destroy = ModulatorDestroy; + state->state.DeviceUpdate = ModulatorDeviceUpdate; + state->state.Update = ModulatorUpdate; + state->state.Process = ModulatorProcess; + + state->index = 0.0f; + state->step = 1.0f; + + state->Scale = 1.0f; + + state->iirFilter.coeff = 0.0f; + state->iirFilter.history[0] = 0.0f; + + return &state->state; +} diff --git a/project/jni/openal/src/Alc/alcReverb.c b/project/jni/openal/src/Alc/alcReverb.c new file mode 100644 index 000000000..6ca47d2dc --- /dev/null +++ b/project/jni/openal/src/Alc/alcReverb.c @@ -0,0 +1,1329 @@ +/** + * Reverb for the OpenAL cross platform audio library + * Copyright (C) 2008-2009 by Christopher Fitzgerald. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alEffect.h" +#include "alError.h" +#include "alu.h" + +typedef struct DelayLine +{ + // The delay lines use sample lengths that are powers of 2 to allow the + // use of bit-masking instead of a modulus for wrapping. + ALuint Mask; + ALfloat *Line; +} DelayLine; + +typedef struct ALverbState { + // Must be first in all effects! + ALeffectState state; + + // All delay lines are allocated as a single buffer to reduce memory + // fragmentation and management code. + ALfloat *SampleBuffer; + ALuint TotalSamples; + // Master effect low-pass filter (2 chained 1-pole filters). + FILTER LpFilter; + ALfloat LpHistory[2]; + struct { + // Modulator delay line. + DelayLine Delay; + // The vibrato time is tracked with an index over a modulus-wrapped + // range (in samples). + ALuint Index; + ALuint Range; + // The depth of frequency change (also in samples) and its filter. + ALfloat Depth; + ALfloat Coeff; + ALfloat Filter; + } Mod; + // Initial effect delay. + DelayLine Delay; + // The tap points for the initial delay. First tap goes to early + // reflections, the last to late reverb. + ALuint DelayTap[2]; + struct { + // Output gain for early reflections. + ALfloat Gain; + // Early reflections are done with 4 delay lines. + ALfloat Coeff[4]; + DelayLine Delay[4]; + ALuint Offset[4]; + // The gain for each output channel based on 3D panning (only for the + // EAX path). + ALfloat PanGain[OUTPUTCHANNELS]; + } Early; + // Decorrelator delay line. + DelayLine Decorrelator; + // There are actually 4 decorrelator taps, but the first occurs at the + // initial sample. + ALuint DecoTap[3]; + struct { + // Output gain for late reverb. + ALfloat Gain; + // Attenuation to compensate for the modal density and decay rate of + // the late lines. + ALfloat DensityGain; + // The feed-back and feed-forward all-pass coefficient. + ALfloat ApFeedCoeff; + // Mixing matrix coefficient. + ALfloat MixCoeff; + // Late reverb has 4 parallel all-pass filters. + ALfloat ApCoeff[4]; + DelayLine ApDelay[4]; + ALuint ApOffset[4]; + // In addition to 4 cyclical delay lines. + ALfloat Coeff[4]; + DelayLine Delay[4]; + ALuint Offset[4]; + // The cyclical delay lines are 1-pole low-pass filtered. + ALfloat LpCoeff[4]; + ALfloat LpSample[4]; + // The gain for each output channel based on 3D panning (only for the + // EAX path). + ALfloat PanGain[OUTPUTCHANNELS]; + } Late; + struct { + // Attenuation to compensate for the modal density and decay rate of + // the echo line. + ALfloat DensityGain; + // Echo delay and all-pass lines. + DelayLine Delay; + DelayLine ApDelay; + ALfloat Coeff; + ALfloat ApFeedCoeff; + ALfloat ApCoeff; + ALuint Offset; + ALuint ApOffset; + // The echo line is 1-pole low-pass filtered. + ALfloat LpCoeff; + ALfloat LpSample; + // Echo mixing coefficients. + ALfloat MixCoeff[2]; + } Echo; + // The current read offset for all delay lines. + ALuint Offset; + + // Gain scale to account for device down-mixing + ALfloat Scale; +} ALverbState; + +/* This coefficient is used to define the maximum frequency range controlled + * by the modulation depth. The current value of 0.1 will allow it to swing + * from 0.9x to 1.1x. This value must be below 1. At 1 it will cause the + * sampler to stall on the downswing, and above 1 it will cause it to sample + * backwards. + */ +static const ALfloat MODULATION_DEPTH_COEFF = 0.1f; + +/* A filter is used to avoid the terrible distortion caused by changing + * modulation time and/or depth. To be consistent across different sample + * rates, the coefficient must be raised to a constant divided by the sample + * rate: coeff^(constant / rate). + */ +static const ALfloat MODULATION_FILTER_COEFF = 0.048f; +static const ALfloat MODULATION_FILTER_CONST = 100000.0f; + +// When diffusion is above 0, an all-pass filter is used to take the edge off +// the echo effect. It uses the following line length (in seconds). +static const ALfloat ECHO_ALLPASS_LENGTH = 0.0133f; + +// Input into the late reverb is decorrelated between four channels. Their +// timings are dependent on a fraction and multiplier. See the +// UpdateDecorrelator() routine for the calculations involved. +static const ALfloat DECO_FRACTION = 0.15f; +static const ALfloat DECO_MULTIPLIER = 2.0f; + +// All delay line lengths are specified in seconds. + +// The lengths of the early delay lines. +static const ALfloat EARLY_LINE_LENGTH[4] = +{ + 0.0015f, 0.0045f, 0.0135f, 0.0405f +}; + +// The lengths of the late all-pass delay lines. +static const ALfloat ALLPASS_LINE_LENGTH[4] = +{ + 0.0151f, 0.0167f, 0.0183f, 0.0200f, +}; + +// The lengths of the late cyclical delay lines. +static const ALfloat LATE_LINE_LENGTH[4] = +{ + 0.0211f, 0.0311f, 0.0461f, 0.0680f +}; + +// The late cyclical delay lines have a variable length dependent on the +// effect's density parameter (inverted for some reason) and this multiplier. +static const ALfloat LATE_LINE_MULTIPLIER = 4.0f; + +// Calculate the length of a delay line and store its mask and offset. +static ALuint CalcLineLength(ALfloat length, ALintptrEXT offset, ALuint frequency, DelayLine *Delay) +{ + ALuint samples; + + // All line lengths are powers of 2, calculated from their lengths, with + // an additional sample in case of rounding errors. + samples = NextPowerOf2((ALuint)(length * frequency) + 1); + // All lines share a single sample buffer. + Delay->Mask = samples - 1; + Delay->Line = (ALfloat*)offset; + // Return the sample count for accumulation. + return samples; +} + +// Given the allocated sample buffer, this function updates each delay line +// offset. +static __inline ALvoid RealizeLineOffset(ALfloat * sampleBuffer, DelayLine *Delay) +{ + Delay->Line = &sampleBuffer[(ALintptrEXT)Delay->Line]; +} + +/* Calculates the delay line metrics and allocates the shared sample buffer + * for all lines given a flag indicating whether or not to allocate the EAX- + * related delays (eaxFlag) and the sample rate (frequency). If an + * allocation failure occurs, it returns AL_FALSE. + */ +static ALboolean AllocLines(ALboolean eaxFlag, ALuint frequency, ALverbState *State) +{ + ALuint totalSamples, index; + ALfloat length; + ALfloat *newBuffer = NULL; + + // All delay line lengths are calculated to accomodate the full range of + // lengths given their respective paramters. + totalSamples = 0; + if(eaxFlag) + { + /* The modulator's line length is calculated from the maximum + * modulation time and depth coefficient, and halfed for the low-to- + * high frequency swing. An additional sample is added to keep it + * stable when there is no modulation. + */ + length = (AL_EAXREVERB_MAX_MODULATION_TIME * MODULATION_DEPTH_COEFF / + 2.0f) + (1.0f / frequency); + totalSamples += CalcLineLength(length, totalSamples, frequency, + &State->Mod.Delay); + } + + // The initial delay is the sum of the reflections and late reverb + // delays. + if(eaxFlag) + length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + + AL_EAXREVERB_MAX_LATE_REVERB_DELAY; + else + length = AL_REVERB_MAX_REFLECTIONS_DELAY + + AL_REVERB_MAX_LATE_REVERB_DELAY; + totalSamples += CalcLineLength(length, totalSamples, frequency, + &State->Delay); + + // The early reflection lines. + for(index = 0;index < 4;index++) + totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples, + frequency, &State->Early.Delay[index]); + + // The decorrelator line is calculated from the lowest reverb density (a + // parameter value of 1). + length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) * + LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER); + totalSamples += CalcLineLength(length, totalSamples, frequency, + &State->Decorrelator); + + // The late all-pass lines. + for(index = 0;index < 4;index++) + totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples, + frequency, &State->Late.ApDelay[index]); + + // The late delay lines are calculated from the lowest reverb density. + for(index = 0;index < 4;index++) + { + length = LATE_LINE_LENGTH[index] * (1.0f + LATE_LINE_MULTIPLIER); + totalSamples += CalcLineLength(length, totalSamples, frequency, + &State->Late.Delay[index]); + } + + if(eaxFlag) + { + // The echo all-pass and delay lines. + totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples, + frequency, &State->Echo.ApDelay); + totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples, + frequency, &State->Echo.Delay); + } + + if(totalSamples != State->TotalSamples) + { + newBuffer = realloc(State->SampleBuffer, sizeof(ALfloat) * totalSamples); + if(newBuffer == NULL) + return AL_FALSE; + State->SampleBuffer = newBuffer; + State->TotalSamples = totalSamples; + } + + // Update all delays to reflect the new sample buffer. + RealizeLineOffset(State->SampleBuffer, &State->Delay); + RealizeLineOffset(State->SampleBuffer, &State->Decorrelator); + for(index = 0;index < 4;index++) + { + RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]); + RealizeLineOffset(State->SampleBuffer, &State->Late.ApDelay[index]); + RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[index]); + } + if(eaxFlag) + { + RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay); + RealizeLineOffset(State->SampleBuffer, &State->Echo.ApDelay); + RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay); + } + + // Clear the sample buffer. + for(index = 0;index < State->TotalSamples;index++) + State->SampleBuffer[index] = 0.0f; + + return AL_TRUE; +} + +// Calculate a decay coefficient given the length of each cycle and the time +// until the decay reaches -60 dB. +static __inline ALfloat CalcDecayCoeff(ALfloat length, ALfloat decayTime) +{ + return aluPow(10.0f, length / decayTime * -60.0f / 20.0f); +} + +// Calculate a decay length from a coefficient and the time until the decay +// reaches -60 dB. +static __inline ALfloat CalcDecayLength(ALfloat coeff, ALfloat decayTime) +{ + return log10(coeff) / -60.0 * 20.0f * decayTime; +} + +// Calculate the high frequency parameter for the I3DL2 coefficient +// calculation. +static __inline ALfloat CalcI3DL2HFreq(ALfloat hfRef, ALuint frequency) +{ + return cos(2.0f * M_PI * hfRef / frequency); +} + +// Calculate an attenuation to be applied to the input of any echo models to +// compensate for modal density and decay time. +static __inline ALfloat CalcDensityGain(ALfloat a) +{ + /* The energy of a signal can be obtained by finding the area under the + * squared signal. This takes the form of Sum(x_n^2), where x is the + * amplitude for the sample n. + * + * Decaying feedback matches exponential decay of the form Sum(a^n), + * where a is the attenuation coefficient, and n is the sample. The area + * under this decay curve can be calculated as: 1 / (1 - a). + * + * Modifying the above equation to find the squared area under the curve + * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be + * calculated by inverting the square root of this approximation, + * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2). + */ + return aluSqrt(1.0f - (a * a)); +} + +// Calculate the mixing matrix coefficients given a diffusion factor. +static __inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y) +{ + ALfloat n, t; + + // The matrix is of order 4, so n is sqrt (4 - 1). + n = aluSqrt(3.0f); + t = diffusion * atan(n); + + // Calculate the first mixing matrix coefficient. + *x = cos(t); + // Calculate the second mixing matrix coefficient. + *y = sin(t) / n; +} + +// Calculate the limited HF ratio for use with the late reverb low-pass +// filters. +static __inline ALfloat CalcLimitedHfRatio(ALfloat hfRatio, ALfloat airAbsorptionGainHF, ALfloat decayTime) +{ + ALfloat limitRatio; + + /* Find the attenuation due to air absorption in dB (converting delay + * time to meters using the speed of sound). Then reversing the decay + * equation, solve for HF ratio. The delay length is cancelled out of + * the equation, so it can be calculated once for all lines. + */ + limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * + SPEEDOFSOUNDMETRESPERSEC); + // Need to limit the result to a minimum of 0.1, just like the HF ratio + // parameter. + limitRatio = __max(limitRatio, 0.1f); + + // Using the limit calculated above, apply the upper bound to the HF + // ratio. + return __min(hfRatio, limitRatio); +} + +// Calculate the coefficient for a HF (and eventually LF) decay damping +// filter. +static __inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloat decayTime, ALfloat decayCoeff, ALfloat cw) +{ + ALfloat coeff, g; + + // Eventually this should boost the high frequencies when the ratio + // exceeds 1. + coeff = 0.0f; + if (hfRatio < 1.0f) + { + // Calculate the low-pass coefficient by dividing the HF decay + // coefficient by the full decay coefficient. + g = CalcDecayCoeff(length, decayTime * hfRatio) / decayCoeff; + + // Damping is done with a 1-pole filter, so g needs to be squared. + g *= g; + coeff = lpCoeffCalc(g, cw); + + // Very low decay times will produce minimal output, so apply an + // upper bound to the coefficient. + coeff = __min(coeff, 0.98f); + } + return coeff; +} + +// Update the EAX modulation index, range, and depth. Keep in mind that this +// kind of vibrato is additive and not multiplicative as one may expect. The +// downswing will sound stronger than the upswing. +static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequency, ALverbState *State) +{ + ALfloat length; + + /* Modulation is calculated in two parts. + * + * The modulation time effects the sinus applied to the change in + * frequency. An index out of the current time range (both in samples) + * is incremented each sample. The range is bound to a reasonable + * minimum (1 sample) and when the timing changes, the index is rescaled + * to the new range (to keep the sinus consistent). + */ + length = modTime * frequency; + if (length >= 1.0f) { + State->Mod.Index = (ALuint)(State->Mod.Index * length / + State->Mod.Range); + State->Mod.Range = (ALuint)length; + } else { + State->Mod.Index = 0; + State->Mod.Range = 1; + } + + /* The modulation depth effects the amount of frequency change over the + * range of the sinus. It needs to be scaled by the modulation time so + * that a given depth produces a consistent change in frequency over all + * ranges of time. Since the depth is applied to a sinus value, it needs + * to be halfed once for the sinus range and again for the sinus swing + * in time (half of it is spent decreasing the frequency, half is spent + * increasing it). + */ + State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f / + 2.0f * frequency; +} + +// Update the offsets for the initial effect delay line. +static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALverbState *State) +{ + // Calculate the initial delay taps. + State->DelayTap[0] = (ALuint)(earlyDelay * frequency); + State->DelayTap[1] = (ALuint)((earlyDelay + lateDelay) * frequency); +} + +// Update the early reflections gain and line coefficients. +static ALvoid UpdateEarlyLines(ALfloat reverbGain, ALfloat earlyGain, ALfloat lateDelay, ALverbState *State) +{ + ALuint index; + + // Calculate the early reflections gain (from the master effect gain, and + // reflections gain parameters) with a constant attenuation of 0.5. + State->Early.Gain = 0.5f * reverbGain * earlyGain; + + // Calculate the gain (coefficient) for each early delay line using the + // late delay time. This expands the early reflections to the start of + // the late reverb. + for(index = 0;index < 4;index++) + State->Early.Coeff[index] = CalcDecayCoeff(EARLY_LINE_LENGTH[index], + lateDelay); +} + +// Update the offsets for the decorrelator line. +static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALverbState *State) +{ + ALuint index; + ALfloat length; + + /* The late reverb inputs are decorrelated to smooth the reverb tail and + * reduce harsh echos. The first tap occurs immediately, while the + * remaining taps are delayed by multiples of a fraction of the smallest + * cyclical delay time. + * + * offset[index] = (FRACTION (MULTIPLIER^index)) smallest_delay + */ + for(index = 0;index < 3;index++) + { + length = (DECO_FRACTION * aluPow(DECO_MULTIPLIER, (ALfloat)index)) * + LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); + State->DecoTap[index] = (ALuint)(length * frequency); + } +} + +// Update the late reverb gains, line lengths, and line coefficients. +static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State) +{ + ALfloat length; + ALuint index; + + /* Calculate the late reverb gain (from the master effect gain, and late + * reverb gain parameters). Since the output is tapped prior to the + * application of the next delay line coefficients, this gain needs to be + * attenuated by the 'x' mixing matrix coefficient as well. + */ + State->Late.Gain = reverbGain * lateGain * xMix; + + /* To compensate for changes in modal density and decay time of the late + * reverb signal, the input is attenuated based on the maximal energy of + * the outgoing signal. This approximation is used to keep the apparent + * energy of the signal equal for all ranges of density and decay time. + * + * The average length of the cyclcical delay lines is used to calculate + * the attenuation coefficient. + */ + length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] + + LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f; + length *= 1.0f + (density * LATE_LINE_MULTIPLIER); + State->Late.DensityGain = CalcDensityGain(CalcDecayCoeff(length, + decayTime)); + + // Calculate the all-pass feed-back and feed-forward coefficient. + State->Late.ApFeedCoeff = 0.5f * aluPow(diffusion, 2.0f); + + for(index = 0;index < 4;index++) + { + // Calculate the gain (coefficient) for each all-pass line. + State->Late.ApCoeff[index] = CalcDecayCoeff(ALLPASS_LINE_LENGTH[index], + decayTime); + + // Calculate the length (in seconds) of each cyclical delay line. + length = LATE_LINE_LENGTH[index] * (1.0f + (density * + LATE_LINE_MULTIPLIER)); + + // Calculate the delay offset for each cyclical delay line. + State->Late.Offset[index] = (ALuint)(length * frequency); + + // Calculate the gain (coefficient) for each cyclical line. + State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime); + + // Calculate the damping coefficient for each low-pass filter. + State->Late.LpCoeff[index] = + CalcDampingCoeff(hfRatio, length, decayTime, + State->Late.Coeff[index], cw); + + // Attenuate the cyclical line coefficients by the mixing coefficient + // (x). + State->Late.Coeff[index] *= xMix; + } +} + +// Update the echo gain, line offset, line coefficients, and mixing +// coefficients. +static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State) +{ + // Update the offset and coefficient for the echo delay line. + State->Echo.Offset = (ALuint)(echoTime * frequency); + + // Calculate the decay coefficient for the echo line. + State->Echo.Coeff = CalcDecayCoeff(echoTime, decayTime); + + // Calculate the energy-based attenuation coefficient for the echo delay + // line. + State->Echo.DensityGain = CalcDensityGain(State->Echo.Coeff); + + // Calculate the echo all-pass feed coefficient. + State->Echo.ApFeedCoeff = 0.5f * aluPow(diffusion, 2.0f); + + // Calculate the echo all-pass attenuation coefficient. + State->Echo.ApCoeff = CalcDecayCoeff(ECHO_ALLPASS_LENGTH, decayTime); + + // Calculate the damping coefficient for each low-pass filter. + State->Echo.LpCoeff = CalcDampingCoeff(hfRatio, echoTime, decayTime, + State->Echo.Coeff, cw); + + /* Calculate the echo mixing coefficients. The first is applied to the + * echo itself. The second is used to attenuate the late reverb when + * echo depth is high and diffusion is low, so the echo is slightly + * stronger than the decorrelated echos in the reverb tail. + */ + State->Echo.MixCoeff[0] = reverbGain * lateGain * echoDepth; + State->Echo.MixCoeff[1] = 1.0f - (echoDepth * 0.5f * (1.0f - diffusion)); +} + +// Update the early and late 3D panning gains. +static ALvoid Update3DPanning(const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat *PanningLUT, ALverbState *State) +{ + ALfloat length; + ALfloat earlyPan[3] = { ReflectionsPan[0], ReflectionsPan[1], + ReflectionsPan[2] }; + ALfloat latePan[3] = { LateReverbPan[0], LateReverbPan[1], + LateReverbPan[2] }; + ALint pos; + ALfloat *speakerGain, dirGain, ambientGain; + ALuint index; + + // Calculate the 3D-panning gains for the early reflections and late + // reverb. + length = earlyPan[0]*earlyPan[0] + earlyPan[1]*earlyPan[1] + earlyPan[2]*earlyPan[2]; + if(length > 1.0f) + { + length = 1.0f / aluSqrt(length); + earlyPan[0] *= length; + earlyPan[1] *= length; + earlyPan[2] *= length; + } + length = latePan[0]*latePan[0] + latePan[1]*latePan[1] + latePan[2]*latePan[2]; + if(length > 1.0f) + { + length = 1.0f / aluSqrt(length); + latePan[0] *= length; + latePan[1] *= length; + latePan[2] *= length; + } + + /* This code applies directional reverb just like the mixer applies + * directional sources. It diffuses the sound toward all speakers as the + * magnitude of the panning vector drops, which is only a rough + * approximation of the expansion of sound across the speakers from the + * panning direction. + */ + pos = aluCart2LUTpos(earlyPan[2], earlyPan[0]); + speakerGain = &PanningLUT[OUTPUTCHANNELS * pos]; + dirGain = aluSqrt((earlyPan[0] * earlyPan[0]) + (earlyPan[2] * earlyPan[2])); + ambientGain = (1.0 - dirGain); + for(index = 0;index < OUTPUTCHANNELS;index++) + State->Early.PanGain[index] = dirGain * speakerGain[index] + ambientGain; + + pos = aluCart2LUTpos(latePan[2], latePan[0]); + speakerGain = &PanningLUT[OUTPUTCHANNELS * pos]; + dirGain = aluSqrt((latePan[0] * latePan[0]) + (latePan[2] * latePan[2])); + ambientGain = (1.0 - dirGain); + for(index = 0;index < OUTPUTCHANNELS;index++) + State->Late.PanGain[index] = dirGain * speakerGain[index] + ambientGain; +} + +// Basic delay line input/output routines. +static __inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset) +{ + return Delay->Line[offset&Delay->Mask]; +} + +static __inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in) +{ + Delay->Line[offset&Delay->Mask] = in; +} + +// Attenuated delay line output routine. +static __inline ALfloat AttenuatedDelayLineOut(DelayLine *Delay, ALuint offset, ALfloat coeff) +{ + return coeff * Delay->Line[offset&Delay->Mask]; +} + +// Basic attenuated all-pass input/output routine. +static __inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff) +{ + ALfloat out, feed; + + out = DelayLineOut(Delay, outOffset); + feed = feedCoeff * in; + DelayLineIn(Delay, inOffset, (feedCoeff * (out - feed)) + in); + + // The time-based attenuation is only applied to the delay output to + // keep it from affecting the feed-back path (which is already controlled + // by the all-pass feed coefficient). + return (coeff * out) - feed; +} + +// Given an input sample, this function produces modulation for the late +// reverb. +static __inline ALfloat EAXModulation(ALverbState *State, ALfloat in) +{ + ALfloat sinus, frac; + ALuint offset; + ALfloat out0, out1; + + // Calculate the sinus rythm (dependent on modulation time and the + // sampling rate). The center of the sinus is moved to reduce the delay + // of the effect when the time or depth are low. + sinus = 1.0f - cos(2.0f * M_PI * State->Mod.Index / State->Mod.Range); + + // The depth determines the range over which to read the input samples + // from, so it must be filtered to reduce the distortion caused by even + // small parameter changes. + State->Mod.Filter += (State->Mod.Depth - State->Mod.Filter) * + State->Mod.Coeff; + + // Calculate the read offset and fraction between it and the next sample. + frac = (1.0f + (State->Mod.Filter * sinus)); + offset = (ALuint)frac; + frac -= offset; + + // Get the two samples crossed by the offset, and feed the delay line + // with the next input sample. + out0 = DelayLineOut(&State->Mod.Delay, State->Offset - offset); + out1 = DelayLineOut(&State->Mod.Delay, State->Offset - offset - 1); + DelayLineIn(&State->Mod.Delay, State->Offset, in); + + // Step the modulation index forward, keeping it bound to its range. + State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range; + + // The output is obtained by linearly interpolating the two samples that + // were acquired above. + return out0 + ((out1 - out0) * frac); +} + +// Delay line output routine for early reflections. +static __inline ALfloat EarlyDelayLineOut(ALverbState *State, ALuint index) +{ + return AttenuatedDelayLineOut(&State->Early.Delay[index], + State->Offset - State->Early.Offset[index], + State->Early.Coeff[index]); +} + +// Given an input sample, this function produces four-channel output for the +// early reflections. +static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *out) +{ + ALfloat d[4], v, f[4]; + + // Obtain the decayed results of each early delay line. + d[0] = EarlyDelayLineOut(State, 0); + d[1] = EarlyDelayLineOut(State, 1); + d[2] = EarlyDelayLineOut(State, 2); + d[3] = EarlyDelayLineOut(State, 3); + + /* The following uses a lossless scattering junction from waveguide + * theory. It actually amounts to a householder mixing matrix, which + * will produce a maximally diffuse response, and means this can probably + * be considered a simple feed-back delay network (FDN). + * N + * --- + * \ + * v = 2/N / d_i + * --- + * i=1 + */ + v = (d[0] + d[1] + d[2] + d[3]) * 0.5f; + // The junction is loaded with the input here. + v += in; + + // Calculate the feed values for the delay lines. + f[0] = v - d[0]; + f[1] = v - d[1]; + f[2] = v - d[2]; + f[3] = v - d[3]; + + // Re-feed the delay lines. + DelayLineIn(&State->Early.Delay[0], State->Offset, f[0]); + DelayLineIn(&State->Early.Delay[1], State->Offset, f[1]); + DelayLineIn(&State->Early.Delay[2], State->Offset, f[2]); + DelayLineIn(&State->Early.Delay[3], State->Offset, f[3]); + + // Output the results of the junction for all four channels. + out[0] = State->Early.Gain * f[0]; + out[1] = State->Early.Gain * f[1]; + out[2] = State->Early.Gain * f[2]; + out[3] = State->Early.Gain * f[3]; +} + +// All-pass input/output routine for late reverb. +static __inline ALfloat LateAllPassInOut(ALverbState *State, ALuint index, ALfloat in) +{ + return AllpassInOut(&State->Late.ApDelay[index], + State->Offset - State->Late.ApOffset[index], + State->Offset, in, State->Late.ApFeedCoeff, + State->Late.ApCoeff[index]); +} + +// Delay line output routine for late reverb. +static __inline ALfloat LateDelayLineOut(ALverbState *State, ALuint index) +{ + return AttenuatedDelayLineOut(&State->Late.Delay[index], + State->Offset - State->Late.Offset[index], + State->Late.Coeff[index]); +} + +// Low-pass filter input/output routine for late reverb. +static __inline ALfloat LateLowPassInOut(ALverbState *State, ALuint index, ALfloat in) +{ + State->Late.LpSample[index] = in + + ((State->Late.LpSample[index] - in) * State->Late.LpCoeff[index]); + return State->Late.LpSample[index]; +} + +// Given four decorrelated input samples, this function produces four-channel +// output for the late reverb. +static __inline ALvoid LateReverb(ALverbState *State, ALfloat *in, ALfloat *out) +{ + ALfloat d[4], f[4]; + + // Obtain the decayed results of the cyclical delay lines, and add the + // corresponding input channels. Then pass the results through the + // low-pass filters. + + // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and back + // to 0. + d[0] = LateLowPassInOut(State, 2, in[2] + LateDelayLineOut(State, 2)); + d[1] = LateLowPassInOut(State, 0, in[0] + LateDelayLineOut(State, 0)); + d[2] = LateLowPassInOut(State, 3, in[3] + LateDelayLineOut(State, 3)); + d[3] = LateLowPassInOut(State, 1, in[1] + LateDelayLineOut(State, 1)); + + // To help increase diffusion, run each line through an all-pass filter. + // When there is no diffusion, the shortest all-pass filter will feed the + // shortest delay line. + d[0] = LateAllPassInOut(State, 0, d[0]); + d[1] = LateAllPassInOut(State, 1, d[1]); + d[2] = LateAllPassInOut(State, 2, d[2]); + d[3] = LateAllPassInOut(State, 3, d[3]); + + /* Late reverb is done with a modified feed-back delay network (FDN) + * topology. Four input lines are each fed through their own all-pass + * filter and then into the mixing matrix. The four outputs of the + * mixing matrix are then cycled back to the inputs. Each output feeds + * a different input to form a circlular feed cycle. + * + * The mixing matrix used is a 4D skew-symmetric rotation matrix derived + * using a single unitary rotational parameter: + * + * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 + * [ -a, d, c, -b ] + * [ -b, -c, d, a ] + * [ -c, b, -a, d ] + * + * The rotation is constructed from the effect's diffusion parameter, + * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y + * with differing signs, and d is the coefficient x. The matrix is thus: + * + * [ x, y, -y, y ] n = sqrt(matrix_order - 1) + * [ -y, x, y, y ] t = diffusion_parameter * atan(n) + * [ y, -y, x, y ] x = cos(t) + * [ -y, -y, -y, x ] y = sin(t) / n + * + * To reduce the number of multiplies, the x coefficient is applied with + * the cyclical delay line coefficients. Thus only the y coefficient is + * applied when mixing, and is modified to be: y / x. + */ + f[0] = d[0] + (State->Late.MixCoeff * ( d[1] - d[2] + d[3])); + f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3])); + f[2] = d[2] + (State->Late.MixCoeff * ( d[0] - d[1] + d[3])); + f[3] = d[3] + (State->Late.MixCoeff * (-d[0] - d[1] - d[2])); + + // Output the results of the matrix for all four channels, attenuated by + // the late reverb gain (which is attenuated by the 'x' mix coefficient). + out[0] = State->Late.Gain * f[0]; + out[1] = State->Late.Gain * f[1]; + out[2] = State->Late.Gain * f[2]; + out[3] = State->Late.Gain * f[3]; + + // Re-feed the cyclical delay lines. + DelayLineIn(&State->Late.Delay[0], State->Offset, f[0]); + DelayLineIn(&State->Late.Delay[1], State->Offset, f[1]); + DelayLineIn(&State->Late.Delay[2], State->Offset, f[2]); + DelayLineIn(&State->Late.Delay[3], State->Offset, f[3]); +} + +// Given an input sample, this function mixes echo into the four-channel late +// reverb. +static __inline ALvoid EAXEcho(ALverbState *State, ALfloat in, ALfloat *late) +{ + ALfloat out, feed; + + // Get the latest attenuated echo sample for output. + feed = AttenuatedDelayLineOut(&State->Echo.Delay, + State->Offset - State->Echo.Offset, + State->Echo.Coeff); + + // Mix the output into the late reverb channels. + out = State->Echo.MixCoeff[0] * feed; + late[0] = (State->Echo.MixCoeff[1] * late[0]) + out; + late[1] = (State->Echo.MixCoeff[1] * late[1]) + out; + late[2] = (State->Echo.MixCoeff[1] * late[2]) + out; + late[3] = (State->Echo.MixCoeff[1] * late[3]) + out; + + // Mix the energy-attenuated input with the output and pass it through + // the echo low-pass filter. + feed += State->Echo.DensityGain * in; + feed += ((State->Echo.LpSample - feed) * State->Echo.LpCoeff); + State->Echo.LpSample = feed; + + // Then the echo all-pass filter. + feed = AllpassInOut(&State->Echo.ApDelay, + State->Offset - State->Echo.ApOffset, + State->Offset, feed, State->Echo.ApFeedCoeff, + State->Echo.ApCoeff); + + // Feed the delay with the mixed and filtered sample. + DelayLineIn(&State->Echo.Delay, State->Offset, feed); +} + +// Perform the non-EAX reverb pass on a given input sample, resulting in +// four-channel output. +static __inline ALvoid VerbPass(ALverbState *State, ALfloat in, ALfloat *early, ALfloat *late) +{ + ALfloat feed, taps[4]; + + // Low-pass filter the incoming sample. + in = lpFilter2P(&State->LpFilter, 0, in); + + // Feed the initial delay line. + DelayLineIn(&State->Delay, State->Offset, in); + + // Calculate the early reflection from the first delay tap. + in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]); + EarlyReflection(State, in, early); + + // Feed the decorrelator from the energy-attenuated output of the second + // delay tap. + in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]); + feed = in * State->Late.DensityGain; + DelayLineIn(&State->Decorrelator, State->Offset, feed); + + // Calculate the late reverb from the decorrelator taps. + taps[0] = feed; + taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]); + taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]); + taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]); + LateReverb(State, taps, late); + + // Step all delays forward one sample. + State->Offset++; +} + +// Perform the EAX reverb pass on a given input sample, resulting in four- +// channel output. +static __inline ALvoid EAXVerbPass(ALverbState *State, ALfloat in, ALfloat *early, ALfloat *late) +{ + ALfloat feed, taps[4]; + + // Low-pass filter the incoming sample. + in = lpFilter2P(&State->LpFilter, 0, in); + + // Perform any modulation on the input. + in = EAXModulation(State, in); + + // Feed the initial delay line. + DelayLineIn(&State->Delay, State->Offset, in); + + // Calculate the early reflection from the first delay tap. + in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]); + EarlyReflection(State, in, early); + + // Feed the decorrelator from the energy-attenuated output of the second + // delay tap. + in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]); + feed = in * State->Late.DensityGain; + DelayLineIn(&State->Decorrelator, State->Offset, feed); + + // Calculate the late reverb from the decorrelator taps. + taps[0] = feed; + taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]); + taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]); + taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]); + LateReverb(State, taps, late); + + // Calculate and mix in any echo. + EAXEcho(State, in, late); + + // Step all delays forward one sample. + State->Offset++; +} + +// This destroys the reverb state. It should be called only when the effect +// slot has a different (or no) effect loaded over the reverb effect. +static ALvoid VerbDestroy(ALeffectState *effect) +{ + ALverbState *State = (ALverbState*)effect; + if(State) + { + free(State->SampleBuffer); + State->SampleBuffer = NULL; + free(State); + } +} + +// This updates the device-dependant reverb state. This is called on +// initialization and any time the device parameters (eg. playback frequency, +// or format) have been changed. +static ALboolean VerbDeviceUpdate(ALeffectState *effect, ALCdevice *Device) +{ + ALverbState *State = (ALverbState*)effect; + ALuint frequency = Device->Frequency, index; + + // Allocate the delay lines. + if(!AllocLines(AL_FALSE, frequency, State)) + return AL_FALSE; + + State->Scale = aluSqrt(Device->NumChan / 8.0f); + + // The early reflection and late all-pass filter line lengths are static, + // so their offsets only need to be calculated once. + for(index = 0;index < 4;index++) + { + State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] * + frequency); + State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] * + frequency); + } + + return AL_TRUE; +} + +// This updates the device-dependant EAX reverb state. This is called on +// initialization and any time the device parameters (eg. playback frequency, +// format) have been changed. +static ALboolean EAXVerbDeviceUpdate(ALeffectState *effect, ALCdevice *Device) +{ + ALverbState *State = (ALverbState*)effect; + ALuint frequency = Device->Frequency, index; + + // Allocate the delay lines. + if(!AllocLines(AL_TRUE, frequency, State)) + return AL_FALSE; + + State->Scale = aluSqrt(Device->NumChan / 8.0f); + + // Calculate the modulation filter coefficient. Notice that the exponent + // is calculated given the current sample rate. This ensures that the + // resulting filter response over time is consistent across all sample + // rates. + State->Mod.Coeff = aluPow(MODULATION_FILTER_COEFF, + MODULATION_FILTER_CONST / frequency); + + // The early reflection and late all-pass filter line lengths are static, + // so their offsets only need to be calculated once. + for(index = 0;index < 4;index++) + { + State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] * + frequency); + State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] * + frequency); + } + + // The echo all-pass filter line length is static, so its offset only + // needs to be calculated once. + State->Echo.ApOffset = (ALuint)(ECHO_ALLPASS_LENGTH * frequency); + + return AL_TRUE; +} + +// This updates the reverb state. This is called any time the reverb effect +// is loaded into a slot. +static ALvoid VerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect) +{ + ALverbState *State = (ALverbState*)effect; + ALuint frequency = Context->Device->Frequency; + ALfloat cw, x, y, hfRatio; + + // Calculate the master low-pass filter (from the master effect HF gain). + cw = CalcI3DL2HFreq(Effect->Reverb.HFReference, frequency); + // This is done with 2 chained 1-pole filters, so no need to square g. + State->LpFilter.coeff = lpCoeffCalc(Effect->Reverb.GainHF, cw); + + // Update the initial effect delay. + UpdateDelayLine(Effect->Reverb.ReflectionsDelay, + Effect->Reverb.LateReverbDelay, frequency, State); + + // Update the early lines. + UpdateEarlyLines(Effect->Reverb.Gain, Effect->Reverb.ReflectionsGain, + Effect->Reverb.LateReverbDelay, State); + + // Update the decorrelator. + UpdateDecorrelator(Effect->Reverb.Density, frequency, State); + + // Get the mixing matrix coefficients (x and y). + CalcMatrixCoeffs(Effect->Reverb.Diffusion, &x, &y); + // Then divide x into y to simplify the matrix calculation. + State->Late.MixCoeff = y / x; + + // If the HF limit parameter is flagged, calculate an appropriate limit + // based on the air absorption parameter. + hfRatio = Effect->Reverb.DecayHFRatio; + if(Effect->Reverb.DecayHFLimit && Effect->Reverb.AirAbsorptionGainHF < 1.0f) + hfRatio = CalcLimitedHfRatio(hfRatio, Effect->Reverb.AirAbsorptionGainHF, + Effect->Reverb.DecayTime); + + // Update the late lines. + UpdateLateLines(Effect->Reverb.Gain, Effect->Reverb.LateReverbGain, + x, Effect->Reverb.Density, Effect->Reverb.DecayTime, + Effect->Reverb.Diffusion, hfRatio, cw, frequency, State); +} + +// This updates the EAX reverb state. This is called any time the EAX reverb +// effect is loaded into a slot. +static ALvoid EAXVerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect) +{ + ALverbState *State = (ALverbState*)effect; + ALuint frequency = Context->Device->Frequency; + ALfloat cw, x, y, hfRatio; + + // Calculate the master low-pass filter (from the master effect HF gain). + cw = CalcI3DL2HFreq(Effect->Reverb.HFReference, frequency); + // This is done with 2 chained 1-pole filters, so no need to square g. + State->LpFilter.coeff = lpCoeffCalc(Effect->Reverb.GainHF, cw); + + // Update the modulator line. + UpdateModulator(Effect->Reverb.ModulationTime, + Effect->Reverb.ModulationDepth, frequency, State); + + // Update the initial effect delay. + UpdateDelayLine(Effect->Reverb.ReflectionsDelay, + Effect->Reverb.LateReverbDelay, frequency, State); + + // Update the early lines. + UpdateEarlyLines(Effect->Reverb.Gain, Effect->Reverb.ReflectionsGain, + Effect->Reverb.LateReverbDelay, State); + + // Update the decorrelator. + UpdateDecorrelator(Effect->Reverb.Density, frequency, State); + + // Get the mixing matrix coefficients (x and y). + CalcMatrixCoeffs(Effect->Reverb.Diffusion, &x, &y); + // Then divide x into y to simplify the matrix calculation. + State->Late.MixCoeff = y / x; + + // If the HF limit parameter is flagged, calculate an appropriate limit + // based on the air absorption parameter. + hfRatio = Effect->Reverb.DecayHFRatio; + if(Effect->Reverb.DecayHFLimit && Effect->Reverb.AirAbsorptionGainHF < 1.0f) + hfRatio = CalcLimitedHfRatio(hfRatio, Effect->Reverb.AirAbsorptionGainHF, + Effect->Reverb.DecayTime); + + // Update the late lines. + UpdateLateLines(Effect->Reverb.Gain, Effect->Reverb.LateReverbGain, + x, Effect->Reverb.Density, Effect->Reverb.DecayTime, + Effect->Reverb.Diffusion, hfRatio, cw, frequency, State); + + // Update the echo line. + UpdateEchoLine(Effect->Reverb.Gain, Effect->Reverb.LateReverbGain, + Effect->Reverb.EchoTime, Effect->Reverb.DecayTime, + Effect->Reverb.Diffusion, Effect->Reverb.EchoDepth, + hfRatio, cw, frequency, State); + + // Update early and late 3D panning. + Update3DPanning(Effect->Reverb.ReflectionsPan, Effect->Reverb.LateReverbPan, + Context->Device->PanningLUT, State); +} + +// This processes the reverb state, given the input samples and an output +// buffer. +static ALvoid VerbProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]) +{ + ALverbState *State = (ALverbState*)effect; + ALuint index; + ALfloat early[4], late[4], out[4]; + ALfloat gain = Slot->Gain * State->Scale; + + for(index = 0;index < SamplesToDo;index++) + { + // Process reverb for this sample. + VerbPass(State, SamplesIn[index], early, late); + + // Mix early reflections and late reverb. + out[0] = (early[0] + late[0]) * gain; + out[1] = (early[1] + late[1]) * gain; + out[2] = (early[2] + late[2]) * gain; + out[3] = (early[3] + late[3]) * gain; + + // Output the results. + SamplesOut[index][FRONT_LEFT] += out[0]; + SamplesOut[index][FRONT_RIGHT] += out[1]; + SamplesOut[index][FRONT_CENTER] += out[3]; + SamplesOut[index][SIDE_LEFT] += out[0]; + SamplesOut[index][SIDE_RIGHT] += out[1]; + SamplesOut[index][BACK_LEFT] += out[0]; + SamplesOut[index][BACK_RIGHT] += out[1]; + SamplesOut[index][BACK_CENTER] += out[2]; + } +} + +// This processes the EAX reverb state, given the input samples and an output +// buffer. +static ALvoid EAXVerbProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]) +{ + ALverbState *State = (ALverbState*)effect; + ALuint index; + ALfloat early[4], late[4]; + ALfloat gain = Slot->Gain * State->Scale; + + for(index = 0;index < SamplesToDo;index++) + { + // Process reverb for this sample. + EAXVerbPass(State, SamplesIn[index], early, late); + + // Unfortunately, while the number and configuration of gains for + // panning adjust according to OUTPUTCHANNELS, the output from the + // reverb engine is not so scalable. + SamplesOut[index][FRONT_LEFT] += + (State->Early.PanGain[FRONT_LEFT]*early[0] + + State->Late.PanGain[FRONT_LEFT]*late[0]) * gain; + SamplesOut[index][FRONT_RIGHT] += + (State->Early.PanGain[FRONT_RIGHT]*early[1] + + State->Late.PanGain[FRONT_RIGHT]*late[1]) * gain; + SamplesOut[index][FRONT_CENTER] += + (State->Early.PanGain[FRONT_CENTER]*early[3] + + State->Late.PanGain[FRONT_CENTER]*late[3]) * gain; + SamplesOut[index][SIDE_LEFT] += + (State->Early.PanGain[SIDE_LEFT]*early[0] + + State->Late.PanGain[SIDE_LEFT]*late[0]) * gain; + SamplesOut[index][SIDE_RIGHT] += + (State->Early.PanGain[SIDE_RIGHT]*early[1] + + State->Late.PanGain[SIDE_RIGHT]*late[1]) * gain; + SamplesOut[index][BACK_LEFT] += + (State->Early.PanGain[BACK_LEFT]*early[0] + + State->Late.PanGain[BACK_LEFT]*late[0]) * gain; + SamplesOut[index][BACK_RIGHT] += + (State->Early.PanGain[BACK_RIGHT]*early[1] + + State->Late.PanGain[BACK_RIGHT]*late[1]) * gain; + SamplesOut[index][BACK_CENTER] += + (State->Early.PanGain[BACK_CENTER]*early[2] + + State->Late.PanGain[BACK_CENTER]*late[2]) * gain; + } +} + +// This creates the reverb state. It should be called only when the reverb +// effect is loaded into a slot that doesn't already have a reverb effect. +ALeffectState *VerbCreate(void) +{ + ALverbState *State = NULL; + ALuint index; + + State = malloc(sizeof(ALverbState)); + if(!State) + return NULL; + + State->state.Destroy = VerbDestroy; + State->state.DeviceUpdate = VerbDeviceUpdate; + State->state.Update = VerbUpdate; + State->state.Process = VerbProcess; + + State->TotalSamples = 0; + State->SampleBuffer = NULL; + + State->LpFilter.coeff = 0.0f; + State->LpFilter.history[0] = 0.0f; + State->LpFilter.history[1] = 0.0f; + + State->Mod.Delay.Mask = 0; + State->Mod.Delay.Line = NULL; + State->Mod.Index = 0; + State->Mod.Range = 1; + State->Mod.Depth = 0.0f; + State->Mod.Coeff = 0.0f; + State->Mod.Filter = 0.0f; + + State->Delay.Mask = 0; + State->Delay.Line = NULL; + State->DelayTap[0] = 0; + State->DelayTap[1] = 0; + + State->Early.Gain = 0.0f; + for(index = 0;index < 4;index++) + { + State->Early.Coeff[index] = 0.0f; + State->Early.Delay[index].Mask = 0; + State->Early.Delay[index].Line = NULL; + State->Early.Offset[index] = 0; + } + + State->Decorrelator.Mask = 0; + State->Decorrelator.Line = NULL; + State->DecoTap[0] = 0; + State->DecoTap[1] = 0; + State->DecoTap[2] = 0; + + State->Late.Gain = 0.0f; + State->Late.DensityGain = 0.0f; + State->Late.ApFeedCoeff = 0.0f; + State->Late.MixCoeff = 0.0f; + for(index = 0;index < 4;index++) + { + State->Late.ApCoeff[index] = 0.0f; + State->Late.ApDelay[index].Mask = 0; + State->Late.ApDelay[index].Line = NULL; + State->Late.ApOffset[index] = 0; + + State->Late.Coeff[index] = 0.0f; + State->Late.Delay[index].Mask = 0; + State->Late.Delay[index].Line = NULL; + State->Late.Offset[index] = 0; + + State->Late.LpCoeff[index] = 0.0f; + State->Late.LpSample[index] = 0.0f; + } + + for(index = 0;index < OUTPUTCHANNELS;index++) + { + State->Early.PanGain[index] = 0.0f; + State->Late.PanGain[index] = 0.0f; + } + + State->Echo.DensityGain = 0.0f; + State->Echo.Delay.Mask = 0; + State->Echo.Delay.Line = NULL; + State->Echo.ApDelay.Mask = 0; + State->Echo.ApDelay.Line = NULL; + State->Echo.Coeff = 0.0f; + State->Echo.ApFeedCoeff = 0.0f; + State->Echo.ApCoeff = 0.0f; + State->Echo.Offset = 0; + State->Echo.ApOffset = 0; + State->Echo.LpCoeff = 0.0f; + State->Echo.LpSample = 0.0f; + State->Echo.MixCoeff[0] = 0.0f; + State->Echo.MixCoeff[1] = 0.0f; + + State->Offset = 0; + + State->Scale = 1.0f; + + return &State->state; +} + +ALeffectState *EAXVerbCreate(void) +{ + ALeffectState *State = VerbCreate(); + if(State) + { + State->DeviceUpdate = EAXVerbDeviceUpdate; + State->Update = EAXVerbUpdate; + State->Process = EAXVerbProcess; + } + return State; +} diff --git a/project/jni/openal/src/Alc/alcRing.c b/project/jni/openal/src/Alc/alcRing.c new file mode 100644 index 000000000..3361eb6e5 --- /dev/null +++ b/project/jni/openal/src/Alc/alcRing.c @@ -0,0 +1,131 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" + + +struct RingBuffer { + ALubyte *mem; + + ALsizei frame_size; + ALsizei length; + ALint read_pos; + ALint write_pos; + + CRITICAL_SECTION cs; +}; + + +RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length) +{ + RingBuffer *ring = calloc(1, sizeof(*ring)); + if(ring) + { + ring->frame_size = frame_size; + ring->length = length+1; + ring->write_pos = 1; + ring->mem = malloc(ring->length * ring->frame_size); + if(!ring->mem) + { + free(ring); + ring = NULL; + } + + InitializeCriticalSection(&ring->cs); + } + return ring; +} + +void DestroyRingBuffer(RingBuffer *ring) +{ + if(ring) + { + DeleteCriticalSection(&ring->cs); + free(ring->mem); + free(ring); + } +} + +ALsizei RingBufferSize(RingBuffer *ring) +{ + ALsizei s; + + EnterCriticalSection(&ring->cs); + s = (ring->write_pos-ring->read_pos-1+ring->length) % ring->length; + LeaveCriticalSection(&ring->cs); + + return s; +} + +void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len) +{ + int remain; + + EnterCriticalSection(&ring->cs); + + remain = (ring->read_pos-ring->write_pos+ring->length) % ring->length; + if(remain < len) len = remain; + + if(len > 0) + { + remain = ring->length - ring->write_pos; + if(remain < len) + { + memcpy(ring->mem+(ring->write_pos*ring->frame_size), data, + remain*ring->frame_size); + memcpy(ring->mem, data+(remain*ring->frame_size), + (len-remain)*ring->frame_size); + } + else + memcpy(ring->mem+(ring->write_pos*ring->frame_size), data, + len*ring->frame_size); + + ring->write_pos += len; + ring->write_pos %= ring->length; + } + + LeaveCriticalSection(&ring->cs); +} + +void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len) +{ + int remain; + + EnterCriticalSection(&ring->cs); + + remain = ring->length - ring->read_pos; + if(remain < len) + { + memcpy(data, ring->mem+(ring->read_pos*ring->frame_size), remain*ring->frame_size); + memcpy(data+(remain*ring->frame_size), ring->mem, (len-remain)*ring->frame_size); + } + else + memcpy(data, ring->mem+(ring->read_pos*ring->frame_size), len*ring->frame_size); + + ring->read_pos += len; + ring->read_pos %= ring->length; + + LeaveCriticalSection(&ring->cs); +} diff --git a/project/jni/openal/src/Alc/alcThread.c b/project/jni/openal/src/Alc/alcThread.c new file mode 100644 index 000000000..582dfd8c2 --- /dev/null +++ b/project/jni/openal/src/Alc/alcThread.c @@ -0,0 +1,128 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include + +#include "alMain.h" +#include "alThunk.h" + + +#ifdef _WIN32 + +typedef struct { + ALuint (*func)(ALvoid*); + ALvoid *ptr; + HANDLE thread; +} ThreadInfo; + +static DWORD CALLBACK StarterFunc(void *ptr) +{ + ThreadInfo *inf = (ThreadInfo*)ptr; + ALint ret; + + ret = inf->func(inf->ptr); + ExitThread((DWORD)ret); + + return (DWORD)ret; +} + +ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr) +{ + DWORD dummy; + ThreadInfo *inf = malloc(sizeof(ThreadInfo)); + if(!inf) return 0; + + inf->func = func; + inf->ptr = ptr; + + inf->thread = CreateThread(NULL, 0, StarterFunc, inf, 0, &dummy); + if(!inf->thread) + { + free(inf); + return NULL; + } + + return inf; +} + +ALuint StopThread(ALvoid *thread) +{ + ThreadInfo *inf = thread; + DWORD ret = 0; + + WaitForSingleObject(inf->thread, INFINITE); + GetExitCodeThread(inf->thread, &ret); + CloseHandle(inf->thread); + + free(inf); + + return (ALuint)ret; +} + +#else + +#include + +typedef struct { + ALuint (*func)(ALvoid*); + ALvoid *ptr; + ALuint ret; + pthread_t thread; +} ThreadInfo; + +static void *StarterFunc(void *ptr) +{ + ThreadInfo *inf = (ThreadInfo*)ptr; + inf->ret = inf->func(inf->ptr); + return NULL; +} + +ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr) +{ + ThreadInfo *inf = malloc(sizeof(ThreadInfo)); + if(!inf) return NULL; + + inf->func = func; + inf->ptr = ptr; + if(pthread_create(&inf->thread, NULL, StarterFunc, inf) != 0) + { + free(inf); + return NULL; + } + + return inf; +} + +ALuint StopThread(ALvoid *thread) +{ + ThreadInfo *inf = thread; + ALuint ret; + + pthread_join(inf->thread, NULL); + ret = inf->ret; + + free(inf); + + return ret; +} + +#endif diff --git a/project/jni/openal/src/Alc/android.c b/project/jni/openal/src/Alc/android.c new file mode 100644 index 000000000..66c1f5260 --- /dev/null +++ b/project/jni/openal/src/Alc/android.c @@ -0,0 +1,279 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2010 by Chris Robinson + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" + +static const ALCchar android_device[] = "Android Default"; + +static JavaVM* javaVM = NULL; + +static jclass cAudioTrack = NULL; + +static jmethodID mAudioTrack; +static jmethodID mGetMinBufferSize; +static jmethodID mPlay; +static jmethodID mStop; +static jmethodID mRelease; +static jmethodID mWrite; + +jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + javaVM = vm; + return JNI_VERSION_1_2; +} + +static JNIEnv* GetEnv() +{ + JNIEnv* env = NULL; + if (javaVM) (*javaVM)->GetEnv(javaVM, (void**)&env, JNI_VERSION_1_2); + return env; +} + +typedef struct +{ + pthread_t thread; + volatile int running; +} AndroidData; + +#define STREAM_MUSIC 3 +#define CHANNEL_CONFIGURATION_MONO 2 +#define CHANNEL_CONFIGURATION_STEREO 3 +#define ENCODING_PCM_8BIT 3 +#define ENCODING_PCM_16BIT 2 +#define MODE_STREAM 1 + +static void* thread_function(void* arg) +{ + ALCdevice* device = (ALCdevice*)arg; + AndroidData* data = (AndroidData*)device->ExtraData; + + JNIEnv* env; + (*javaVM)->AttachCurrentThread(javaVM, &env, NULL); + + (*env)->PushLocalFrame(env, 2); + + int sampleRateInHz = device->Frequency; + int channelConfig = aluChannelsFromFormat(device->Format) == 1 ? CHANNEL_CONFIGURATION_MONO : CHANNEL_CONFIGURATION_STEREO; + int audioFormat = aluBytesFromFormat(device->Format) == 1 ? ENCODING_PCM_8BIT : ENCODING_PCM_16BIT; + + int bufferSizeInBytes = (*env)->CallStaticIntMethod(env, cAudioTrack, + mGetMinBufferSize, sampleRateInHz, channelConfig, audioFormat); + + int bufferSizeInSamples = bufferSizeInBytes / aluFrameSizeFromFormat(device->Format); + + jobject track = (*env)->NewObject(env, cAudioTrack, mAudioTrack, + STREAM_MUSIC, sampleRateInHz, channelConfig, audioFormat, device->NumUpdates * bufferSizeInBytes, MODE_STREAM); + + (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mPlay); + + jarray buffer = (*env)->NewByteArray(env, bufferSizeInBytes); + + while (data->running) + { + void* pBuffer = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL); + + if (pBuffer) + { + aluMixData(device, pBuffer, bufferSizeInSamples); + (*env)->ReleasePrimitiveArrayCritical(env, buffer, pBuffer, 0); + + (*env)->CallNonvirtualIntMethod(env, track, cAudioTrack, mWrite, buffer, 0, bufferSizeInBytes); + } + else + { + AL_PRINT("Failed to get pointer to array bytes"); + } + } + + (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mStop); + (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mRelease); + + (*env)->PopLocalFrame(env, NULL); + + (*javaVM)->DetachCurrentThread(javaVM); + return NULL; +} + +static ALCboolean android_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + JNIEnv* env = GetEnv(); + AndroidData* data; + int channels; + int bytes; + + if (!cAudioTrack) + { + /* Cache AudioTrack class and it's method id's + * And do this only once! + */ + + cAudioTrack = (*env)->FindClass(env, "android/media/AudioTrack"); + if (!cAudioTrack) + { + AL_PRINT("android.media.AudioTrack class is not found. Are you running at least 1.5 version?"); + return ALC_FALSE; + } + + cAudioTrack = (*env)->NewGlobalRef(env, cAudioTrack); + + mAudioTrack = (*env)->GetMethodID(env, cAudioTrack, "", "(IIIIII)V"); + mGetMinBufferSize = (*env)->GetStaticMethodID(env, cAudioTrack, "getMinBufferSize", "(III)I"); + mPlay = (*env)->GetMethodID(env, cAudioTrack, "play", "()V"); + mStop = (*env)->GetMethodID(env, cAudioTrack, "stop", "()V"); + mRelease = (*env)->GetMethodID(env, cAudioTrack, "release", "()V"); + mWrite = (*env)->GetMethodID(env, cAudioTrack, "write", "([BII)I"); + } + + if (!deviceName) + { + deviceName = android_device; + } + else if (strcmp(deviceName, android_device) != 0) + { + return ALC_FALSE; + } + + data = (AndroidData*)calloc(1, sizeof(*data)); + device->szDeviceName = strdup(deviceName); + device->ExtraData = data; + return ALC_TRUE; +} + +static void android_close_playback(ALCdevice *device) +{ + AndroidData* data = (AndroidData*)device->ExtraData; + if (data != NULL) + { + free(data); + device->ExtraData = NULL; + } +} + +static ALCboolean android_reset_playback(ALCdevice *device) +{ + AndroidData* data = (AndroidData*)device->ExtraData; + + if (aluChannelsFromFormat(device->Format) >= 2) + { + device->Format = aluBytesFromFormat(device->Format) >= 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO8; + } + else + { + device->Format = aluBytesFromFormat(device->Format) >= 2 ? AL_FORMAT_MONO16 : AL_FORMAT_MONO8; + } + + SetDefaultChannelOrder(device); + + data->running = 1; + pthread_create(&data->thread, NULL, thread_function, device); + + return ALC_TRUE; +} + +static void android_stop_playback(ALCdevice *device) +{ + AndroidData* data = (AndroidData*)device->ExtraData; + + if (data->running) + { + data->running = 0; + pthread_join(data->thread, NULL); + } +} + +static ALCboolean android_open_capture(ALCdevice *pDevice, const ALCchar *deviceName) +{ + (void)pDevice; + (void)deviceName; + return ALC_FALSE; +} + +static void android_close_capture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void android_start_capture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void android_stop_capture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void android_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) +{ + (void)pDevice; + (void)pBuffer; + (void)lSamples; +} + +static ALCuint android_available_samples(ALCdevice *pDevice) +{ + (void)pDevice; + return 0; +} + +static const BackendFuncs android_funcs = { + android_open_playback, + android_close_playback, + android_reset_playback, + android_stop_playback, + android_open_capture, + android_close_capture, + android_start_capture, + android_stop_capture, + android_capture_samples, + android_available_samples +}; + +void alc_android_init(BackendFuncs *func_list) +{ + *func_list = android_funcs; +} + +void alc_android_deinit(void) +{ + JNIEnv* env = GetEnv(); + + /* release cached AudioTrack class */ + (*env)->DeleteGlobalRef(env, cAudioTrack); +} + +void alc_android_probe(int type) +{ + if (type == DEVICE_PROBE) + { + AppendDeviceList(android_device); + } + else if (type == ALL_DEVICE_PROBE) + { + AppendAllDeviceList(android_device); + } +} diff --git a/project/jni/openal/src/Alc/bs2b.c b/project/jni/openal/src/Alc/bs2b.c new file mode 100644 index 000000000..9930e1184 --- /dev/null +++ b/project/jni/openal/src/Alc/bs2b.c @@ -0,0 +1,201 @@ +/*- + * Copyright (c) 2005 Boris Mikhaylov + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include + +#include "bs2b.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +/* Single pole IIR filter. + * O[n] = a0*I[n] + a1*I[n-1] + b1*O[n-1] + */ + +/* Lowpass filter */ +#define lo_filter(in, out_1) (bs2b->a0_lo*(in) + bs2b->b1_lo*(out_1)) + +/* Highboost filter */ +#define hi_filter(in, in_1, out_1) (bs2b->a0_hi*(in) + bs2b->a1_hi*(in_1) + bs2b->b1_hi*(out_1)) + +/* Set up all data. */ +static void init(struct bs2b *bs2b) +{ + double Fc_lo, Fc_hi; + double G_lo, G_hi; + double x; + + if ((bs2b->srate > 192000) || (bs2b->srate < 2000)) + bs2b->srate = BS2B_DEFAULT_SRATE; + + switch(bs2b->level) + { + case BS2B_LOW_CLEVEL: /* Low crossfeed level */ + Fc_lo = 360.0; + Fc_hi = 501.0; + G_lo = 0.398107170553497; + G_hi = 0.205671765275719; + break; + + case BS2B_MIDDLE_CLEVEL: /* Middle crossfeed level */ + Fc_lo = 500.0; + Fc_hi = 711.0; + G_lo = 0.459726988530872; + G_hi = 0.228208484414988; + break; + + case BS2B_HIGH_CLEVEL: /* High crossfeed level (virtual speakers are closer to itself) */ + Fc_lo = 700.0; + Fc_hi = 1021.0; + G_lo = 0.530884444230988; + G_hi = 0.250105790667544; + break; + + case BS2B_LOW_ECLEVEL: /* Low easy crossfeed level */ + Fc_lo = 360.0; + Fc_hi = 494.0; + G_lo = 0.316227766016838; + G_hi = 0.168236228897329; + break; + + case BS2B_MIDDLE_ECLEVEL: /* Middle easy crossfeed level */ + Fc_lo = 500.0; + Fc_hi = 689.0; + G_lo = 0.354813389233575; + G_hi = 0.187169483835901; + break; + + default: /* High easy crossfeed level */ + bs2b->level = BS2B_HIGH_ECLEVEL; + + Fc_lo = 700.0; + Fc_hi = 975.0; + G_lo = 0.398107170553497; + G_hi = 0.205671765275719; + break; + } /* switch */ + + /* $fc = $Fc / $s; + * $d = 1 / 2 / pi / $fc; + * $x = exp(-1 / $d); + */ + + x = exp(-2.0 * M_PI * Fc_lo / bs2b->srate); + bs2b->b1_lo = x; + bs2b->a0_lo = G_lo * (1.0 - x); + + x = exp(-2.0 * M_PI * Fc_hi / bs2b->srate); + bs2b->b1_hi = x; + bs2b->a0_hi = 1.0 - G_hi * (1.0 - x); + bs2b->a1_hi = -x; + + bs2b->gain = 1.0 / (1.0 - G_hi + G_lo); +} /* init */ + +/* Exported functions. + * See descriptions in "bs2b.h" + */ + +void bs2b_set_level(struct bs2b *bs2b, int level) +{ + if(level == bs2b->level) + return; + bs2b->level = level; + init(bs2b); +} /* bs2b_set_level */ + +int bs2b_get_level(struct bs2b *bs2b) +{ + return bs2b->level; +} /* bs2b_get_level */ + +void bs2b_set_srate(struct bs2b *bs2b, int srate) +{ + if (srate == bs2b->srate) + return; + bs2b->srate = srate; + init(bs2b); +} /* bs2b_set_srate */ + +int bs2b_get_srate(struct bs2b *bs2b) +{ + return bs2b->srate; +} /* bs2b_get_srate */ + +void bs2b_clear(struct bs2b *bs2b) +{ + int loopv = sizeof(bs2b->last_sample); + + while (loopv) + { + ((char *)&bs2b->last_sample)[--loopv] = 0; + } +} /* bs2b_clear */ + +int bs2b_is_clear(struct bs2b *bs2b) +{ + int loopv = sizeof(bs2b->last_sample); + + while (loopv) + { + if (((char *)&bs2b->last_sample)[--loopv] != 0) + return 0; + } + return 1; +} /* bs2b_is_clear */ + +void bs2b_cross_feed(struct bs2b *bs2b, float *sample) +{ + /* Lowpass filter */ + bs2b->last_sample.lo[0] = lo_filter(sample[0], bs2b->last_sample.lo[0]); + bs2b->last_sample.lo[1] = lo_filter(sample[1], bs2b->last_sample.lo[1]); + + /* Highboost filter */ + bs2b->last_sample.hi[0] = hi_filter(sample[0], bs2b->last_sample.asis[0], bs2b->last_sample.hi[0]); + bs2b->last_sample.hi[1] = hi_filter(sample[1], bs2b->last_sample.asis[1], bs2b->last_sample.hi[1]); + bs2b->last_sample.asis[0] = sample[0]; + bs2b->last_sample.asis[1] = sample[1]; + + /* Crossfeed */ + sample[0] = bs2b->last_sample.hi[0] + bs2b->last_sample.lo[1]; + sample[1] = bs2b->last_sample.hi[1] + bs2b->last_sample.lo[0]; + + /* Bass boost cause allpass attenuation */ + sample[0] *= bs2b->gain; + sample[1] *= bs2b->gain; + + /* Clipping of overloaded samples */ +#if 0 + if (sample[0] > 1.0) + sample[0] = 1.0; + if (sample[0] < -1.0) + sample[0] = -1.0; + if (sample[1] > 1.0) + sample[1] = 1.0; + if (sample[1] < -1.0) + sample[1] = -1.0; +#endif +} /* bs2b_cross_feed */ diff --git a/project/jni/openal/src/Alc/null.c b/project/jni/openal/src/Alc/null.c new file mode 100644 index 000000000..86726fc37 --- /dev/null +++ b/project/jni/openal/src/Alc/null.c @@ -0,0 +1,176 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2010 by Chris Robinson + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" + + +typedef struct { + ALvoid *buffer; + ALuint size; + + volatile int killNow; + ALvoid *thread; +} null_data; + + +static const ALCchar nullDevice[] = "Null Output"; + +static ALuint NullProc(ALvoid *ptr) +{ + ALCdevice *Device = (ALCdevice*)ptr; + null_data *data = (null_data*)Device->ExtraData; + ALuint frameSize; + ALuint now, last; + ALuint avail; + + frameSize = aluFrameSizeFromFormat(Device->Format); + + last = timeGetTime()<<8; + while(!data->killNow && Device->Connected) + { + now = timeGetTime()<<8; + + avail = (ALuint64)(now-last) * Device->Frequency / (1000<<8); + if(avail < Device->UpdateSize) + { + Sleep(1); + continue; + } + + while(avail >= Device->UpdateSize) + { + aluMixData(Device, data->buffer, Device->UpdateSize); + + avail -= Device->UpdateSize; + last += (ALuint64)Device->UpdateSize * (1000<<8) / Device->Frequency; + } + } + + return 0; +} + +static ALCboolean null_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + null_data *data; + + if(!deviceName) + deviceName = nullDevice; + else if(strcmp(deviceName, nullDevice) != 0) + return ALC_FALSE; + + data = (null_data*)calloc(1, sizeof(*data)); + + device->szDeviceName = strdup(deviceName); + device->ExtraData = data; + return ALC_TRUE; +} + +static void null_close_playback(ALCdevice *device) +{ + null_data *data = (null_data*)device->ExtraData; + + free(data); + device->ExtraData = NULL; +} + +static ALCboolean null_reset_playback(ALCdevice *device) +{ + null_data *data = (null_data*)device->ExtraData; + + data->size = device->UpdateSize * aluFrameSizeFromFormat(device->Format); + data->buffer = malloc(data->size); + if(!data->buffer) + { + AL_PRINT("buffer malloc failed\n"); + return ALC_FALSE; + } + SetDefaultWFXChannelOrder(device); + + data->thread = StartThread(NullProc, device); + if(data->thread == NULL) + { + free(data->buffer); + data->buffer = NULL; + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void null_stop_playback(ALCdevice *device) +{ + null_data *data = (null_data*)device->ExtraData; + + if(!data->thread) + return; + + data->killNow = 1; + StopThread(data->thread); + data->thread = NULL; + + data->killNow = 0; + + free(data->buffer); + data->buffer = NULL; +} + + +static ALCboolean null_open_capture(ALCdevice *device, const ALCchar *deviceName) +{ + (void)device; + (void)deviceName; + return ALC_FALSE; +} + + +BackendFuncs null_funcs = { + null_open_playback, + null_close_playback, + null_reset_playback, + null_stop_playback, + null_open_capture, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +void alc_null_init(BackendFuncs *func_list) +{ + *func_list = null_funcs; +} + +void alc_null_deinit(void) +{ +} + +void alc_null_probe(int type) +{ + if(type == DEVICE_PROBE) + AppendDeviceList(nullDevice); + else if(type == ALL_DEVICE_PROBE) + AppendAllDeviceList(nullDevice); +} diff --git a/project/jni/openal/src/OpenAL32/Include/alAuxEffectSlot.h b/project/jni/openal/src/OpenAL32/Include/alAuxEffectSlot.h new file mode 100644 index 000000000..9a916dd81 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/Include/alAuxEffectSlot.h @@ -0,0 +1,60 @@ +#ifndef _AL_AUXEFFECTSLOT_H_ +#define _AL_AUXEFFECTSLOT_H_ + +#include "AL/al.h" +#include "alEffect.h" +#include "alFilter.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ALeffectState ALeffectState; + +typedef struct ALeffectslot +{ + ALeffect effect; + + ALfloat Gain; + ALboolean AuxSendAuto; + + ALeffectState *EffectState; + + ALfloat WetBuffer[BUFFERSIZE]; + + ALuint refcount; + + // Index to itself + ALuint effectslot; + + struct ALeffectslot *next; +} ALeffectslot; + + +ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context); + + +struct ALeffectState { + ALvoid (*Destroy)(ALeffectState *State); + ALboolean (*DeviceUpdate)(ALeffectState *State, ALCdevice *Device); + ALvoid (*Update)(ALeffectState *State, ALCcontext *Context, const ALeffect *Effect); + ALvoid (*Process)(ALeffectState *State, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]); +}; + +ALeffectState *NoneCreate(void); +ALeffectState *EAXVerbCreate(void); +ALeffectState *VerbCreate(void); +ALeffectState *EchoCreate(void); +ALeffectState *ModulatorCreate(void); + +#define ALEffect_Destroy(a) ((a)->Destroy((a))) +#define ALEffect_DeviceUpdate(a,b) ((a)->DeviceUpdate((a),(b))) +#define ALEffect_Update(a,b,c) ((a)->Update((a),(b),(c))) +#define ALEffect_Process(a,b,c,d,e) ((a)->Process((a),(b),(c),(d),(e))) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/jni/openal/src/OpenAL32/Include/alBuffer.h b/project/jni/openal/src/OpenAL32/Include/alBuffer.h new file mode 100644 index 000000000..7d3d59acf --- /dev/null +++ b/project/jni/openal/src/OpenAL32/Include/alBuffer.h @@ -0,0 +1,39 @@ +#ifndef _AL_BUFFER_H_ +#define _AL_BUFFER_H_ + +#include "AL/al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define BUFFER_PADDING 2 + +typedef struct ALbuffer +{ + ALfloat *data; + ALsizei size; + + ALenum format; + ALenum eOriginalFormat; + ALsizei frequency; + + ALsizei OriginalSize; + ALsizei OriginalAlign; + + ALsizei LoopStart; + ALsizei LoopEnd; + + ALuint refcount; // Number of sources using this buffer (deletion can only occur when this is 0) + + // Index to itself + ALuint buffer; +} ALbuffer; + +ALvoid ReleaseALBuffers(ALCdevice *device); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/jni/openal/src/OpenAL32/Include/alDatabuffer.h b/project/jni/openal/src/OpenAL32/Include/alDatabuffer.h new file mode 100644 index 000000000..221855283 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/Include/alDatabuffer.h @@ -0,0 +1,33 @@ +#ifndef _AL_DATABUFFER_H_ +#define _AL_DATABUFFER_H_ + +#include "AL/al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UNMAPPED 0 +#define MAPPED 1 + +typedef struct ALdatabuffer +{ + ALubyte *data; + ALintptrEXT size; + + ALenum state; + ALenum usage; + + /* Index to self */ + ALuint databuffer; + + struct ALdatabuffer *next; +} ALdatabuffer; + +ALvoid ReleaseALDatabuffers(ALCdevice *device); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/jni/openal/src/OpenAL32/Include/alEffect.h b/project/jni/openal/src/OpenAL32/Include/alEffect.h new file mode 100644 index 000000000..500b60a1f --- /dev/null +++ b/project/jni/openal/src/OpenAL32/Include/alEffect.h @@ -0,0 +1,83 @@ +// NOTE: The effect structure is getting too large, it may be a good idea to +// start using a union or another form of unified storage. +#ifndef _AL_EFFECT_H_ +#define _AL_EFFECT_H_ + +#include "AL/al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + EAXREVERB = 0, + REVERB, + ECHO, + MODULATOR, + + MAX_EFFECTS +}; +extern ALboolean DisabledEffects[MAX_EFFECTS]; + +typedef struct ALeffect +{ + // Effect type (AL_EFFECT_NULL, ...) + ALenum type; + + struct { + // Shared Reverb Properties + ALfloat Density; + ALfloat Diffusion; + ALfloat Gain; + ALfloat GainHF; + ALfloat DecayTime; + ALfloat DecayHFRatio; + ALfloat ReflectionsGain; + ALfloat ReflectionsDelay; + ALfloat LateReverbGain; + ALfloat LateReverbDelay; + ALfloat AirAbsorptionGainHF; + ALfloat RoomRolloffFactor; + ALboolean DecayHFLimit; + + // Additional EAX Reverb Properties + ALfloat GainLF; + ALfloat DecayLFRatio; + ALfloat ReflectionsPan[3]; + ALfloat LateReverbPan[3]; + ALfloat EchoTime; + ALfloat EchoDepth; + ALfloat ModulationTime; + ALfloat ModulationDepth; + ALfloat HFReference; + ALfloat LFReference; + } Reverb; + + struct { + ALfloat Delay; + ALfloat LRDelay; + + ALfloat Damping; + ALfloat Feedback; + + ALfloat Spread; + } Echo; + + struct { + ALfloat Frequency; + ALfloat HighPassCutoff; + ALint Waveform; + } Modulator; + + // Index to itself + ALuint effect; +} ALeffect; + + +ALvoid ReleaseALEffects(ALCdevice *device); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/jni/openal/src/OpenAL32/Include/alError.h b/project/jni/openal/src/OpenAL32/Include/alError.h new file mode 100644 index 000000000..7976e50f9 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/Include/alError.h @@ -0,0 +1,17 @@ +#ifndef _AL_ERROR_H_ +#define _AL_ERROR_H_ + +#include "AL/al.h" +#include "AL/alc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +ALvoid alSetError(ALCcontext *Context, ALenum errorCode); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/jni/openal/src/OpenAL32/Include/alFilter.h b/project/jni/openal/src/OpenAL32/Include/alFilter.h new file mode 100644 index 000000000..9f420d354 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/Include/alFilter.h @@ -0,0 +1,101 @@ +#ifndef _AL_FILTER_H_ +#define _AL_FILTER_H_ + +#include "AL/al.h" +#include "alu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + ALfloat coeff; +#ifndef _MSC_VER + ALfloat history[0]; +#else + ALfloat history[1]; +#endif +} FILTER; + +static __inline ALfloat lpFilter4P(FILTER *iir, ALuint offset, ALfloat input) +{ + ALfloat *history = &iir->history[offset]; + ALfloat a = iir->coeff; + ALfloat output = input; + + output = output + (history[0]-output)*a; + history[0] = output; + output = output + (history[1]-output)*a; + history[1] = output; + output = output + (history[2]-output)*a; + history[2] = output; + output = output + (history[3]-output)*a; + history[3] = output; + + return output; +} + +static __inline ALfloat lpFilter2P(FILTER *iir, ALuint offset, ALfloat input) +{ + ALfloat *history = &iir->history[offset]; + ALfloat a = iir->coeff; + ALfloat output = input; + + output = output + (history[0]-output)*a; + history[0] = output; + output = output + (history[1]-output)*a; + history[1] = output; + + return output; +} + +static __inline ALfloat lpFilter1P(FILTER *iir, ALuint offset, ALfloat input) +{ + ALfloat *history = &iir->history[offset]; + ALfloat a = iir->coeff; + ALfloat output = input; + + output = output + (history[0]-output)*a; + history[0] = output; + + return output; +} + +/* Calculates the low-pass filter coefficient given the pre-scaled gain and + * cos(w) value. Note that g should be pre-scaled (sqr(gain) for one-pole, + * sqrt(gain) for four-pole, etc) */ +static __inline ALfloat lpCoeffCalc(ALfloat g, ALfloat cw) +{ + ALfloat a = 0.0f; + + /* Be careful with gains < 0.01, as that causes the coefficient + * head towards 1, which will flatten the signal */ + g = __max(g, 0.01f); + if(g < 0.9999f) /* 1-epsilon */ + a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / + (1 - g); + + return a; +} + + +typedef struct ALfilter +{ + // Filter type (AL_FILTER_NULL, ...) + ALenum type; + + ALfloat Gain; + ALfloat GainHF; + + // Index to itself + ALuint filter; +} ALfilter; + + +ALvoid ReleaseALFilters(ALCdevice *device); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/jni/openal/src/OpenAL32/Include/alListener.h b/project/jni/openal/src/OpenAL32/Include/alListener.h new file mode 100644 index 000000000..467193e35 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/Include/alListener.h @@ -0,0 +1,24 @@ +#ifndef _AL_LISTENER_H_ +#define _AL_LISTENER_H_ + +#include "AL/al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ALlistener_struct +{ + ALfloat Position[3]; + ALfloat Velocity[3]; + ALfloat Forward[3]; + ALfloat Up[3]; + ALfloat Gain; + ALfloat MetersPerUnit; +} ALlistener; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/jni/openal/src/OpenAL32/Include/alMain.h b/project/jni/openal/src/OpenAL32/Include/alMain.h new file mode 100644 index 000000000..e7c767642 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/Include/alMain.h @@ -0,0 +1,497 @@ +#ifndef AL_MAIN_H +#define AL_MAIN_H + +#include +#include +#include + +#ifdef HAVE_FENV_H +#include +#endif + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#ifndef AL_EXT_buffer_sub_data +#define AL_EXT_buffer_sub_data 1 +#define AL_BYTE_RW_OFFSETS_EXT 0x1031 +#define AL_SAMPLE_RW_OFFSETS_EXT 0x1032 +typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATAEXTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alBufferSubDataEXT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length); +#endif +#endif + +#ifndef AL_EXT_sample_buffer_object +#define AL_EXT_sample_buffer_object 1 +typedef ptrdiff_t ALintptrEXT; +typedef ptrdiff_t ALsizeiptrEXT; +#define AL_SAMPLE_SOURCE_EXT 0x1040 +#define AL_SAMPLE_SINK_EXT 0x1041 +#define AL_READ_ONLY_EXT 0x1042 +#define AL_WRITE_ONLY_EXT 0x1043 +#define AL_READ_WRITE_EXT 0x1044 +#define AL_STREAM_WRITE_EXT 0x1045 +#define AL_STREAM_READ_EXT 0x1046 +#define AL_STREAM_COPY_EXT 0x1047 +#define AL_STATIC_WRITE_EXT 0x1048 +#define AL_STATIC_READ_EXT 0x1049 +#define AL_STATIC_COPY_EXT 0x104A +#define AL_DYNAMIC_WRITE_EXT 0x104B +#define AL_DYNAMIC_READ_EXT 0x104C +#define AL_DYNAMIC_COPY_EXT 0x104D +typedef ALvoid (AL_APIENTRY*PFNALGENDATABUFFERSEXTPROC)(ALsizei n,ALuint *puiBuffers); +typedef ALvoid (AL_APIENTRY*PFNALDELETEDATABUFFERSEXTPROC)(ALsizei n, const ALuint *puiBuffers); +typedef ALboolean (AL_APIENTRY*PFNALISDATABUFFEREXTPROC)(ALuint uiBuffer); +typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERDATAEXTPROC)(ALuint buffer,const ALvoid *data,ALsizeiptrEXT size,ALenum usage); +typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERSUBDATAEXTPROC)(ALuint buffer, ALintptrEXT start, ALsizeiptrEXT length, const ALvoid *); +typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERSUBDATAEXTPROC)(ALuint buffer, ALintptrEXT start, ALsizeiptrEXT length, ALvoid *); +typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERFEXTPROC)(ALuint buffer, ALenum eParam, ALfloat flValue); +typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERFVEXTPROC)(ALuint buffer, ALenum eParam, const ALfloat* flValues); +typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERIEXTPROC)(ALuint buffer, ALenum eParam, ALint lValue); +typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERIVEXTPROC)(ALuint buffer, ALenum eParam, const ALint* plValues); +typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERFEXTPROC)(ALuint buffer, ALenum eParam, ALfloat *pflValue); +typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERFVEXTPROC)(ALuint buffer, ALenum eParam, ALfloat* pflValues); +typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERIEXTPROC)(ALuint buffer, ALenum eParam, ALint *plValue); +typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERIVEXTPROC)(ALuint buffer, ALenum eParam, ALint* plValues); +typedef ALvoid (AL_APIENTRY*PFNALSELECTDATABUFFEREXTPROC)(ALenum target, ALuint uiBuffer); +typedef ALvoid* (AL_APIENTRY*PFNALMAPDATABUFFEREXTPROC)(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, ALenum access); +typedef ALvoid (AL_APIENTRY*PFNALUNMAPDATABUFFEREXTPROC)(ALuint uiBuffer); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alGenDatabuffersEXT(ALsizei n,ALuint *puiBuffers); +AL_API ALvoid AL_APIENTRY alDeleteDatabuffersEXT(ALsizei n, const ALuint *puiBuffers); +AL_API ALboolean AL_APIENTRY alIsDatabufferEXT(ALuint uiBuffer); +AL_API ALvoid AL_APIENTRY alDatabufferDataEXT(ALuint buffer,const ALvoid *data,ALsizeiptrEXT size,ALenum usage); +AL_API ALvoid AL_APIENTRY alDatabufferSubDataEXT(ALuint buffer, ALintptrEXT start, ALsizeiptrEXT length, const ALvoid *data); +AL_API ALvoid AL_APIENTRY alGetDatabufferSubDataEXT(ALuint buffer, ALintptrEXT start, ALsizeiptrEXT length, ALvoid *data); +AL_API ALvoid AL_APIENTRY alDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alDatabufferfvEXT(ALuint buffer, ALenum eParam, const ALfloat* flValues); +AL_API ALvoid AL_APIENTRY alDatabufferiEXT(ALuint buffer, ALenum eParam, ALint lValue); +AL_API ALvoid AL_APIENTRY alDatabufferivEXT(ALuint buffer, ALenum eParam, const ALint* plValues); +AL_API ALvoid AL_APIENTRY alGetDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetDatabufferfvEXT(ALuint buffer, ALenum eParam, ALfloat* pflValues); +AL_API ALvoid AL_APIENTRY alGetDatabufferiEXT(ALuint buffer, ALenum eParam, ALint *plValue); +AL_API ALvoid AL_APIENTRY alGetDatabufferivEXT(ALuint buffer, ALenum eParam, ALint* plValues); +AL_API ALvoid AL_APIENTRY alSelectDatabufferEXT(ALenum target, ALuint uiBuffer); +AL_API ALvoid* AL_APIENTRY alMapDatabufferEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, ALenum access); +AL_API ALvoid AL_APIENTRY alUnmapDatabufferEXT(ALuint uiBuffer); +#endif +#endif + +#ifndef AL_EXT_loop_points +#define AL_EXT_loop_points 1 +#define AL_LOOP_POINTS 0x2015 +#endif + +#if defined(HAVE_STDINT_H) +#include +typedef int64_t ALint64; +typedef uint64_t ALuint64; +#elif defined(HAVE___INT64) +typedef __int64 ALint64; +typedef unsigned __int64 ALuint64; +#elif (SIZEOF_LONG == 8) +typedef long ALint64; +typedef unsigned long ALuint64; +#elif (SIZEOF_LONG_LONG == 8) +typedef long long ALint64; +typedef unsigned long long ALuint64; +#endif + +#ifdef HAVE_GCC_FORMAT +#define PRINTF_STYLE(x, y) __attribute__((format(printf, (x), (y)))) +#else +#define PRINTF_STYLE(x, y) +#endif + +#ifdef _WIN32 + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif +#include + +typedef DWORD tls_type; +#define tls_create(x) (*(x) = TlsAlloc()) +#define tls_delete(x) TlsFree((x)) +#define tls_get(x) TlsGetValue((x)) +#define tls_set(x, a) TlsSetValue((x), (a)) + +#else + +#include +#include +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif +#include +#include +#include + +#ifdef ANDROID +#include +#endif + +#define IsBadWritePtr(a,b) ((a) == NULL && (b) != 0) + +typedef pthread_key_t tls_type; +#define tls_create(x) pthread_key_create((x), NULL) +#define tls_delete(x) pthread_key_delete((x)) +#define tls_get(x) pthread_getspecific((x)) +#define tls_set(x, a) pthread_setspecific((x), (a)) + +typedef pthread_mutex_t CRITICAL_SECTION; +static __inline void EnterCriticalSection(CRITICAL_SECTION *cs) +{ + int ret; + ret = pthread_mutex_lock(cs); + assert(ret == 0); +} +static __inline void LeaveCriticalSection(CRITICAL_SECTION *cs) +{ + int ret; + ret = pthread_mutex_unlock(cs); + assert(ret == 0); +} +static __inline void InitializeCriticalSection(CRITICAL_SECTION *cs) +{ + pthread_mutexattr_t attrib; + int ret; + + ret = pthread_mutexattr_init(&attrib); + assert(ret == 0); + + ret = pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE); +#ifdef HAVE_PTHREAD_NP_H + if(ret != 0) + ret = pthread_mutexattr_setkind_np(&attrib, PTHREAD_MUTEX_RECURSIVE); +#endif + assert(ret == 0); + ret = pthread_mutex_init(cs, &attrib); + assert(ret == 0); + + pthread_mutexattr_destroy(&attrib); +} + +static __inline void DeleteCriticalSection(CRITICAL_SECTION *cs) +{ + int ret; + ret = pthread_mutex_destroy(cs); + assert(ret == 0); +} + +/* NOTE: This wrapper isn't quite accurate as it returns an ALuint, as opposed + * to the expected DWORD. Both are defined as unsigned 32-bit types, however. + * Additionally, Win32 is supposed to measure the time since Windows started, + * as opposed to the actual time. */ +static __inline ALuint timeGetTime(void) +{ + int ret; +#if _POSIX_TIMERS > 0 + struct timespec ts; + + ret = clock_gettime(CLOCK_REALTIME, &ts); + assert(ret == 0); + + return ts.tv_nsec/1000000 + ts.tv_sec*1000; +#else + struct timeval tv; + + ret = gettimeofday(&tv, NULL); + assert(ret == 0); + + return tv.tv_usec/1000 + tv.tv_sec*1000; +#endif +} + +static __inline void Sleep(ALuint t) +{ + struct timespec tv, rem; + tv.tv_nsec = (t*1000000)%1000000000; + tv.tv_sec = t/1000; + + while(nanosleep(&tv, &rem) == -1 && errno == EINTR) + tv = rem; +} +#define min(x,y) (((x)<(y))?(x):(y)) +#define max(x,y) (((x)>(y))?(x):(y)) +#endif + +#include "alListener.h" +#include "alu.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define SWMIXER_OUTPUT_RATE 44100 + +#define SPEEDOFSOUNDMETRESPERSEC (343.3f) +#define AIRABSORBGAINDBHF (-0.05f) + +#define LOWPASSFREQCUTOFF (5000) + +#define DEFAULT_HEAD_DAMPEN (0.25f) + + +// Find the next power-of-2 for non-power-of-2 numbers. +static __inline ALuint NextPowerOf2(ALuint value) +{ + ALuint powerOf2 = 1; + + if(value) + { + value--; + while(value) + { + value >>= 1; + powerOf2 <<= 1; + } + } + return powerOf2; +} + + +typedef struct { + ALCboolean (*OpenPlayback)(ALCdevice*, const ALCchar*); + void (*ClosePlayback)(ALCdevice*); + ALCboolean (*ResetPlayback)(ALCdevice*); + void (*StopPlayback)(ALCdevice*); + + ALCboolean (*OpenCapture)(ALCdevice*, const ALCchar*); + void (*CloseCapture)(ALCdevice*); + void (*StartCapture)(ALCdevice*); + void (*StopCapture)(ALCdevice*); + void (*CaptureSamples)(ALCdevice*, void*, ALCuint); + ALCuint (*AvailableSamples)(ALCdevice*); +} BackendFuncs; + +enum { + DEVICE_PROBE, + ALL_DEVICE_PROBE, + CAPTURE_DEVICE_PROBE +}; + +void alc_alsa_init(BackendFuncs *func_list); +void alc_alsa_deinit(void); +void alc_alsa_probe(int type); +void alc_oss_init(BackendFuncs *func_list); +void alc_oss_deinit(void); +void alc_oss_probe(int type); +void alc_solaris_init(BackendFuncs *func_list); +void alc_solaris_deinit(void); +void alc_solaris_probe(int type); +void alcDSoundInit(BackendFuncs *func_list); +void alcDSoundDeinit(void); +void alcDSoundProbe(int type); +void alcWinMMInit(BackendFuncs *FuncList); +void alcWinMMDeinit(void); +void alcWinMMProbe(int type); +void alc_pa_init(BackendFuncs *func_list); +void alc_pa_deinit(void); +void alc_pa_probe(int type); +void alc_wave_init(BackendFuncs *func_list); +void alc_wave_deinit(void); +void alc_wave_probe(int type); +void alc_pulse_init(BackendFuncs *func_list); +void alc_pulse_deinit(void); +void alc_pulse_probe(int type); +void alc_android_init(BackendFuncs *func_list); +void alc_android_deinit(void); +void alc_android_probe(int type); +void alc_null_init(BackendFuncs *func_list); +void alc_null_deinit(void); +void alc_null_probe(int type); + + +typedef struct UIntMap { + struct { + ALuint key; + ALvoid *value; + } *array; + ALsizei size; + ALsizei maxsize; +} UIntMap; + +void InitUIntMap(UIntMap *map); +void ResetUIntMap(UIntMap *map); +ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value); +void RemoveUIntMapKey(UIntMap *map, ALuint key); + +static __inline ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key) +{ + if(map->size > 0) + { + ALsizei low = 0; + ALsizei high = map->size - 1; + while(low < high) + { + ALsizei mid = low + (high-low)/2; + if(map->array[mid].key < key) + low = mid + 1; + else + high = mid; + } + if(map->array[low].key == key) + return map->array[low].value; + } + return NULL; +} + + +struct ALCdevice_struct +{ + ALCboolean Connected; + ALboolean IsCaptureDevice; + + ALuint Frequency; + ALuint UpdateSize; + ALuint NumUpdates; + ALenum Format; + + ALCchar *szDeviceName; + + ALCenum LastError; + + // Maximum number of sources that can be created + ALuint MaxNoOfSources; + // Maximum number of slots that can be created + ALuint AuxiliaryEffectSlotMax; + + ALCuint NumMonoSources; + ALCuint NumStereoSources; + ALuint NumAuxSends; + + // Map of Buffers for this device + UIntMap BufferMap; + + // Map of Effects for this device + UIntMap EffectMap; + + // Map of Filters for this device + UIntMap FilterMap; + + // Map of Databuffers for this device + UIntMap DatabufferMap; + + // Stereo-to-binaural filter + struct bs2b *Bs2b; + ALCint Bs2bLevel; + + // Simulated dampening from head occlusion + ALfloat HeadDampen; + + // Duplicate stereo sources on the side/rear channels + ALboolean DuplicateStereo; + + // Dry path buffer mix + float DryBuffer[BUFFERSIZE][OUTPUTCHANNELS]; + + ALuint DevChannels[OUTPUTCHANNELS]; + + ALfloat ChannelMatrix[OUTPUTCHANNELS][OUTPUTCHANNELS]; + + Channel Speaker2Chan[OUTPUTCHANNELS]; + ALfloat PanningLUT[OUTPUTCHANNELS * LUT_NUM]; + ALuint NumChan; + + // Contexts created on this device + ALCcontext **Contexts; + ALuint NumContexts; + + BackendFuncs *Funcs; + void *ExtraData; // For the backend's use + + ALCdevice *next; +}; + +#define ALCdevice_OpenPlayback(a,b) ((a)->Funcs->OpenPlayback((a), (b))) +#define ALCdevice_ClosePlayback(a) ((a)->Funcs->ClosePlayback((a))) +#define ALCdevice_ResetPlayback(a) ((a)->Funcs->ResetPlayback((a))) +#define ALCdevice_StopPlayback(a) ((a)->Funcs->StopPlayback((a))) +#define ALCdevice_OpenCapture(a,b) ((a)->Funcs->OpenCapture((a), (b))) +#define ALCdevice_CloseCapture(a) ((a)->Funcs->CloseCapture((a))) +#define ALCdevice_StartCapture(a) ((a)->Funcs->StartCapture((a))) +#define ALCdevice_StopCapture(a) ((a)->Funcs->StopCapture((a))) +#define ALCdevice_CaptureSamples(a,b,c) ((a)->Funcs->CaptureSamples((a), (b), (c))) +#define ALCdevice_AvailableSamples(a) ((a)->Funcs->AvailableSamples((a))) + +struct ALCcontext_struct +{ + ALlistener Listener; + + UIntMap SourceMap; + UIntMap EffectSlotMap; + + struct ALdatabuffer *SampleSource; + struct ALdatabuffer *SampleSink; + + ALenum LastError; + + ALboolean Suspended; + + ALenum DistanceModel; + ALboolean SourceDistanceModel; + + ALfloat DopplerFactor; + ALfloat DopplerVelocity; + ALfloat flSpeedOfSound; + + struct ALsource **ActiveSources; + ALsizei ActiveSourceCount; + ALsizei MaxActiveSources; + + ALCdevice *Device; + const ALCchar *ExtensionList; + + ALCcontext *next; +}; + +ALCvoid ReleaseALC(ALCvoid); + +void AppendDeviceList(const ALCchar *name); +void AppendAllDeviceList(const ALCchar *name); +void AppendCaptureDeviceList(const ALCchar *name); + +ALCvoid alcSetError(ALCdevice *device, ALenum errorCode); + +ALCvoid SuspendContext(ALCcontext *context); +ALCvoid ProcessContext(ALCcontext *context); + +ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr); +ALuint StopThread(ALvoid *thread); + +ALCcontext *GetContextSuspended(void); + +typedef struct RingBuffer RingBuffer; +RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length); +void DestroyRingBuffer(RingBuffer *ring); +ALsizei RingBufferSize(RingBuffer *ring); +void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len); +void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len); + +void ReadALConfig(void); +void FreeALConfig(void); +int ConfigValueExists(const char *blockName, const char *keyName); +const char *GetConfigValue(const char *blockName, const char *keyName, const char *def); +int GetConfigValueInt(const char *blockName, const char *keyName, int def); +float GetConfigValueFloat(const char *blockName, const char *keyName, float def); +int GetConfigValueBool(const char *blockName, const char *keyName, int def); + +void SetRTPriority(void); + +void SetDefaultChannelOrder(ALCdevice *device); +void SetDefaultWFXChannelOrder(ALCdevice *device); + +void al_print(const char *fname, unsigned int line, const char *fmt, ...) + PRINTF_STYLE(3,4); +#define AL_PRINT(...) al_print(__FILE__, __LINE__, __VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/jni/openal/src/OpenAL32/Include/alSource.h b/project/jni/openal/src/OpenAL32/Include/alSource.h new file mode 100644 index 000000000..0802cbaa5 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/Include/alSource.h @@ -0,0 +1,115 @@ +#ifndef _AL_SOURCE_H_ +#define _AL_SOURCE_H_ + +#define MAX_SENDS 2 + +#include "alFilter.h" +#include "alu.h" +#include "AL/al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + POINT_RESAMPLER = 0, + LINEAR_RESAMPLER, + COSINE_RESAMPLER, + + RESAMPLER_MAX, + RESAMPLER_MIN = -1, + RESAMPLER_DEFAULT = LINEAR_RESAMPLER +} resampler_t; +extern resampler_t DefaultResampler; + +typedef struct ALbufferlistitem +{ + struct ALbuffer *buffer; + struct ALbufferlistitem *next; +} ALbufferlistitem; + +typedef struct ALsource +{ + ALfloat flPitch; + ALfloat flGain; + ALfloat flOuterGain; + ALfloat flMinGain; + ALfloat flMaxGain; + ALfloat flInnerAngle; + ALfloat flOuterAngle; + ALfloat flRefDistance; + ALfloat flMaxDistance; + ALfloat flRollOffFactor; + ALfloat vPosition[3]; + ALfloat vVelocity[3]; + ALfloat vOrientation[3]; + ALboolean bHeadRelative; + ALboolean bLooping; + ALenum DistanceModel; + + resampler_t Resampler; + + ALenum state; + ALuint position; + ALuint position_fraction; + + struct ALbuffer *Buffer; + + struct ALbufferlistitem *queue; // Linked list of buffers in queue + ALuint BuffersInQueue; // Number of buffers in queue + ALuint BuffersPlayed; // Number of buffers played on this loop + + ALfilter DirectFilter; + + struct { + struct ALeffectslot *Slot; + ALfilter WetFilter; + } Send[MAX_SENDS]; + + ALboolean DryGainHFAuto; + ALboolean WetGainAuto; + ALboolean WetGainHFAuto; + ALfloat OuterGainHF; + + ALfloat AirAbsorptionFactor; + ALfloat RoomRolloffFactor; + ALfloat DopplerFactor; + + ALint lOffset; + ALint lOffsetType; + + // Source Type (Static, Streaming, or Undetermined) + ALint lSourceType; + + // Current gains, which are ramped while mixed + ALfloat DryGains[OUTPUTCHANNELS]; + ALfloat WetGains[MAX_SENDS]; + ALboolean FirstStart; + + // Current target parameters used for mixing + ALboolean NeedsUpdate; + struct { + ALfloat DryGains[OUTPUTCHANNELS]; + ALfloat WetGains[MAX_SENDS]; + ALfloat Pitch; + + struct { + FILTER iirFilter; + ALfloat history[OUTPUTCHANNELS]; + } Send[MAX_SENDS]; + + FILTER iirFilter; + ALfloat history[OUTPUTCHANNELS*2]; + } Params; + + // Index to itself + ALuint source; +} ALsource; + +ALvoid ReleaseALSources(ALCcontext *Context); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/jni/openal/src/OpenAL32/Include/alState.h b/project/jni/openal/src/OpenAL32/Include/alState.h new file mode 100644 index 000000000..332176b03 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/Include/alState.h @@ -0,0 +1,14 @@ +#ifndef _AL_STATE_H_ +#define _AL_STATE_H_ + +#include "AL/al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/jni/openal/src/OpenAL32/Include/alThunk.h b/project/jni/openal/src/OpenAL32/Include/alThunk.h new file mode 100644 index 000000000..8fc0e005f --- /dev/null +++ b/project/jni/openal/src/OpenAL32/Include/alThunk.h @@ -0,0 +1,42 @@ +#ifndef _AL_THUNK_H_ +#define _AL_THUNK_H_ + +#include "config.h" + +#include "AL/al.h" +#include "AL/alc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void alThunkInit(void); +void alThunkExit(void); +ALuint alThunkAddEntry(ALvoid * ptr); +void alThunkRemoveEntry(ALuint index); +ALvoid *alThunkLookupEntry(ALuint index); + +#if (SIZEOF_VOIDP > SIZEOF_UINT) + +#define ALTHUNK_INIT() alThunkInit() +#define ALTHUNK_EXIT() alThunkExit() +#define ALTHUNK_ADDENTRY(p) alThunkAddEntry(p) +#define ALTHUNK_REMOVEENTRY(i) alThunkRemoveEntry(i) +#define ALTHUNK_LOOKUPENTRY(i) alThunkLookupEntry(i) + +#else + +#define ALTHUNK_INIT() +#define ALTHUNK_EXIT() +#define ALTHUNK_ADDENTRY(p) ((ALuint)p) +#define ALTHUNK_REMOVEENTRY(i) +#define ALTHUNK_LOOKUPENTRY(i) ((ALvoid*)(i)) + +#endif // (SIZEOF_VOIDP > SIZEOF_INT) + +#ifdef __cplusplus +} +#endif + +#endif //_AL_THUNK_H_ + diff --git a/project/jni/openal/src/OpenAL32/Include/alu.h b/project/jni/openal/src/OpenAL32/Include/alu.h new file mode 100644 index 000000000..55ddbaf65 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/Include/alu.h @@ -0,0 +1,189 @@ +#ifndef _ALU_H_ +#define _ALU_H_ + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#include +#ifdef HAVE_FLOAT_H +#include +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#endif + +#ifdef HAVE_POWF +#define aluPow(x,y) ((ALfloat)powf((float)(x),(float)(y))) +#else +#define aluPow(x,y) ((ALfloat)pow((double)(x),(double)(y))) +#endif + +#ifdef HAVE_SQRTF +#define aluSqrt(x) ((ALfloat)sqrtf((float)(x))) +#else +#define aluSqrt(x) ((ALfloat)sqrt((double)(x))) +#endif + +#ifdef HAVE_ACOSF +#define aluAcos(x) ((ALfloat)acosf((float)(x))) +#else +#define aluAcos(x) ((ALfloat)acos((double)(x))) +#endif + +#ifdef HAVE_ATANF +#define aluAtan(x) ((ALfloat)atanf((float)(x))) +#else +#define aluAtan(x) ((ALfloat)atan((double)(x))) +#endif + +#ifdef HAVE_FABSF +#define aluFabs(x) ((ALfloat)fabsf((float)(x))) +#else +#define aluFabs(x) ((ALfloat)fabs((double)(x))) +#endif + +// fixes for mingw32. +#if defined(max) && !defined(__max) +#define __max max +#endif +#if defined(min) && !defined(__min) +#define __min min +#endif + +#define QUADRANT_NUM 128 +#define LUT_NUM (4 * QUADRANT_NUM) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + FRONT_LEFT = 0, + FRONT_RIGHT, + FRONT_CENTER, + LFE, + BACK_LEFT, + BACK_RIGHT, + BACK_CENTER, + SIDE_LEFT, + SIDE_RIGHT, + + OUTPUTCHANNELS +} Channel; + +#define BUFFERSIZE 8192 + +/* NOTE: The AL_FORMAT_REAR* enums aren't handled here because they're + * converted to AL_FORMAT_QUAD* when loaded */ +static __inline ALuint aluBytesFromFormat(ALenum format) +{ + switch(format) + { + case AL_FORMAT_MONO8: + case AL_FORMAT_STEREO8: + case AL_FORMAT_QUAD8_LOKI: + case AL_FORMAT_QUAD8: + case AL_FORMAT_51CHN8: + case AL_FORMAT_61CHN8: + case AL_FORMAT_71CHN8: + return 1; + + case AL_FORMAT_MONO16: + case AL_FORMAT_STEREO16: + case AL_FORMAT_QUAD16_LOKI: + case AL_FORMAT_QUAD16: + case AL_FORMAT_51CHN16: + case AL_FORMAT_61CHN16: + case AL_FORMAT_71CHN16: + return 2; + + case AL_FORMAT_MONO_FLOAT32: + case AL_FORMAT_STEREO_FLOAT32: + case AL_FORMAT_QUAD32: + case AL_FORMAT_51CHN32: + case AL_FORMAT_61CHN32: + case AL_FORMAT_71CHN32: + return 4; + + case AL_FORMAT_MONO_DOUBLE_EXT: + case AL_FORMAT_STEREO_DOUBLE_EXT: + return 8; + + default: + return 0; + } +} +static __inline ALuint aluChannelsFromFormat(ALenum format) +{ + switch(format) + { + case AL_FORMAT_MONO8: + case AL_FORMAT_MONO16: + case AL_FORMAT_MONO_FLOAT32: + case AL_FORMAT_MONO_DOUBLE_EXT: + return 1; + + case AL_FORMAT_STEREO8: + case AL_FORMAT_STEREO16: + case AL_FORMAT_STEREO_FLOAT32: + case AL_FORMAT_STEREO_DOUBLE_EXT: + return 2; + + case AL_FORMAT_QUAD8_LOKI: + case AL_FORMAT_QUAD16_LOKI: + case AL_FORMAT_QUAD8: + case AL_FORMAT_QUAD16: + case AL_FORMAT_QUAD32: + return 4; + + case AL_FORMAT_51CHN8: + case AL_FORMAT_51CHN16: + case AL_FORMAT_51CHN32: + return 6; + + case AL_FORMAT_61CHN8: + case AL_FORMAT_61CHN16: + case AL_FORMAT_61CHN32: + return 7; + + case AL_FORMAT_71CHN8: + case AL_FORMAT_71CHN16: + case AL_FORMAT_71CHN32: + return 8; + + default: + return 0; + } +} +static __inline ALuint aluFrameSizeFromFormat(ALenum format) +{ + return aluBytesFromFormat(format) * aluChannelsFromFormat(format); +} + +static __inline ALint aluCart2LUTpos(ALfloat re, ALfloat im) +{ + ALint pos = 0; + ALfloat denom = aluFabs(re) + aluFabs(im); + if(denom > 0.0f) + pos = (ALint)(QUADRANT_NUM*aluFabs(im) / denom + 0.5); + + if(re < 0.0) + pos = 2 * QUADRANT_NUM - pos; + if(im < 0.0) + pos = LUT_NUM - pos; + return pos%LUT_NUM; +} + +ALvoid aluInitPanning(ALCdevice *Device); +ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size); +ALvoid aluHandleDisconnect(ALCdevice *device); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/project/jni/openal/src/OpenAL32/Include/bs2b.h b/project/jni/openal/src/OpenAL32/Include/bs2b.h new file mode 100644 index 000000000..4ed576b81 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/Include/bs2b.h @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 2005 Boris Mikhaylov + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef BS2B_H +#define BS2B_H + +/* Number of crossfeed levels */ +#define BS2B_CLEVELS 3 + +/* Normal crossfeed levels */ +#define BS2B_HIGH_CLEVEL 3 +#define BS2B_MIDDLE_CLEVEL 2 +#define BS2B_LOW_CLEVEL 1 + +/* Easy crossfeed levels */ +#define BS2B_HIGH_ECLEVEL BS2B_HIGH_CLEVEL + BS2B_CLEVELS +#define BS2B_MIDDLE_ECLEVEL BS2B_MIDDLE_CLEVEL + BS2B_CLEVELS +#define BS2B_LOW_ECLEVEL BS2B_LOW_CLEVEL + BS2B_CLEVELS + +/* Default crossfeed levels */ +#define BS2B_DEFAULT_CLEVEL BS2B_HIGH_ECLEVEL +/* Default sample rate (Hz) */ +#define BS2B_DEFAULT_SRATE 44100 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct bs2b { + int level; /* Crossfeed level */ + int srate; /* Sample rate (Hz) */ + + /* Lowpass IIR filter coefficients */ + double a0_lo; + double b1_lo; + + /* Highboost IIR filter coefficients */ + double a0_hi; + double a1_hi; + double b1_hi; + + /* Global gain against overloading */ + double gain; + + /* Buffer of last filtered sample. + * [0] - first channel, [1] - second channel + */ + struct t_last_sample { + double asis[2]; + double lo[2]; + double hi[2]; + } last_sample; +}; + +/* Clear buffers and set new coefficients with new crossfeed level value. + * level - crossfeed level of *LEVEL values. + */ +void bs2b_set_level(struct bs2b *bs2b, int level); + +/* Return current crossfeed level value */ +int bs2b_get_level(struct bs2b *bs2b); + +/* Clear buffers and set new coefficients with new sample rate value. + * srate - sample rate by Hz. + */ +void bs2b_set_srate(struct bs2b *bs2b, int srate); + +/* Return current sample rate value */ +int bs2b_get_srate(struct bs2b *bs2b); + +/* Clear buffer */ +void bs2b_clear(struct bs2b *bs2b); + +/* Return 1 if buffer is clear */ +int bs2b_is_clear(struct bs2b *bs2b); + +/* Crossfeeds one stereo sample that are pointed by sample. + * [0] - first channel, [1] - second channel. + * Returns crossfided samle by sample pointer. + */ + +/* sample poits to floats */ +void bs2b_cross_feed(struct bs2b *bs2b, float *sample); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* BS2B_H */ diff --git a/project/jni/openal/src/OpenAL32/alAuxEffectSlot.c b/project/jni/openal/src/OpenAL32/alAuxEffectSlot.c new file mode 100644 index 000000000..e8a76d354 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/alAuxEffectSlot.c @@ -0,0 +1,523 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alThunk.h" +#include "alError.h" +#include "alSource.h" + + +static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect); + +#define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k))) +#define LookupEffect(m, k) ((ALeffect*)LookupUIntMapKey(&(m), (k))) + +AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) +{ + ALCcontext *Context; + ALsizei i=0, j; + + Context = GetContextSuspended(); + if(!Context) return; + + if(n > 0) + { + ALCdevice *Device = Context->Device; + + if(Context->EffectSlotMap.size+n <= (ALsizei)Device->AuxiliaryEffectSlotMax) + { + // Check that enough memory has been allocted in the 'effectslots' array for n Effect Slots + if(!IsBadWritePtr((void*)effectslots, n * sizeof(ALuint))) + { + ALenum err; + + while(i < n) + { + ALeffectslot *slot = calloc(1, sizeof(ALeffectslot)); + if(!slot || !(slot->EffectState=NoneCreate())) + { + free(slot); + // We must have run out or memory + alSetError(Context, AL_OUT_OF_MEMORY); + alDeleteAuxiliaryEffectSlots(i, effectslots); + break; + } + + slot->effectslot = (ALuint)ALTHUNK_ADDENTRY(slot); + err = InsertUIntMapEntry(&Context->EffectSlotMap, + slot->effectslot, slot); + if(err != AL_NO_ERROR) + { + ALTHUNK_REMOVEENTRY(slot->effectslot); + ALEffect_Destroy(slot->EffectState); + free(slot); + + alSetError(Context, err); + alDeleteAuxiliaryEffectSlots(i, effectslots); + break; + } + + effectslots[i++] = slot->effectslot; + + slot->Gain = 1.0; + slot->AuxSendAuto = AL_TRUE; + for(j = 0;j < BUFFERSIZE;j++) + slot->WetBuffer[j] = 0.0f; + slot->refcount = 0; + } + } + } + else + alSetError(Context, AL_INVALID_OPERATION); + } + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) +{ + ALCcontext *Context; + ALeffectslot *EffectSlot; + ALsizei i; + + Context = GetContextSuspended(); + if(!Context) return; + + if (n >= 0) + { + // Check that all effectslots are valid + for (i = 0; i < n; i++) + { + if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslots[i])) == NULL) + { + alSetError(Context, AL_INVALID_NAME); + break; + } + else + { + if(EffectSlot->refcount > 0) + { + alSetError(Context, AL_INVALID_NAME); + break; + } + } + } + + if (i == n) + { + // All effectslots are valid + for (i = 0; i < n; i++) + { + // Recheck that the effectslot is valid, because there could be duplicated names + if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslots[i])) != NULL) + { + ALEffect_Destroy(EffectSlot->EffectState); + + RemoveUIntMapKey(&Context->EffectSlotMap, EffectSlot->effectslot); + ALTHUNK_REMOVEENTRY(EffectSlot->effectslot); + + memset(EffectSlot, 0, sizeof(ALeffectslot)); + free(EffectSlot); + } + } + } + } + else + alSetError(Context, AL_INVALID_VALUE); + + ProcessContext(Context); +} + +AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) +{ + ALCcontext *Context; + ALboolean result; + + Context = GetContextSuspended(); + if(!Context) return AL_FALSE; + + result = (LookupEffectSlot(Context->EffectSlotMap, effectslot) ? + AL_TRUE : AL_FALSE); + + ProcessContext(Context); + + return result; +} + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue) +{ + ALCcontext *Context; + ALboolean updateSources = AL_FALSE; + ALeffectslot *EffectSlot; + + Context = GetContextSuspended(); + if(!Context) return; + + if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL) + { + switch(param) + { + case AL_EFFECTSLOT_EFFECT: { + ALeffect *effect = NULL; + + if(iValue == 0 || + (effect=LookupEffect(Context->Device->EffectMap, iValue)) != NULL) + { + InitializeEffect(Context, EffectSlot, effect); + updateSources = AL_TRUE; + } + else + alSetError(Context, AL_INVALID_VALUE); + } break; + + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + if(iValue == AL_TRUE || iValue == AL_FALSE) + { + EffectSlot->AuxSendAuto = iValue; + updateSources = AL_TRUE; + } + else + alSetError(Context, AL_INVALID_VALUE); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + // Force updating the sources that use this slot, since it affects the + // sending parameters + if(updateSources) + { + ALsizei pos; + for(pos = 0;pos < Context->SourceMap.size;pos++) + { + ALsource *source = Context->SourceMap.array[pos].value; + ALuint i; + for(i = 0;i < MAX_SENDS;i++) + { + if(!source->Send[i].Slot || + source->Send[i].Slot->effectslot != effectslot) + continue; + source->NeedsUpdate = AL_TRUE; + break; + } + } + } + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues) +{ + ALCcontext *Context; + + Context = GetContextSuspended(); + if(!Context) return; + + if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL) + { + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + alAuxiliaryEffectSloti(effectslot, param, piValues[0]); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue) +{ + ALCcontext *Context; + ALeffectslot *EffectSlot; + + Context = GetContextSuspended(); + if(!Context) return; + + if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL) + { + switch(param) + { + case AL_EFFECTSLOT_GAIN: + if(flValue >= 0.0f && flValue <= 1.0f) + EffectSlot->Gain = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues) +{ + ALCcontext *Context; + + Context = GetContextSuspended(); + if(!Context) return; + + if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL) + { + switch(param) + { + case AL_EFFECTSLOT_GAIN: + alAuxiliaryEffectSlotf(effectslot, param, pflValues[0]); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue) +{ + ALCcontext *Context; + ALeffectslot *EffectSlot; + + Context = GetContextSuspended(); + if(!Context) return; + + if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL) + { + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + *piValue = EffectSlot->effect.effect; + break; + + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + *piValue = EffectSlot->AuxSendAuto; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues) +{ + ALCcontext *Context; + + Context = GetContextSuspended(); + if(!Context) return; + + if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL) + { + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + alGetAuxiliaryEffectSloti(effectslot, param, piValues); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue) +{ + ALCcontext *Context; + ALeffectslot *EffectSlot; + + Context = GetContextSuspended(); + if(!Context) return; + + if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL) + { + switch(param) + { + case AL_EFFECTSLOT_GAIN: + *pflValue = EffectSlot->Gain; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues) +{ + ALCcontext *Context; + + Context = GetContextSuspended(); + if(!Context) return; + + if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL) + { + switch(param) + { + case AL_EFFECTSLOT_GAIN: + alGetAuxiliaryEffectSlotf(effectslot, param, pflValues); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + + +static ALvoid NoneDestroy(ALeffectState *State) +{ free(State); } +static ALboolean NoneDeviceUpdate(ALeffectState *State, ALCdevice *Device) +{ + return AL_TRUE; + (void)State; + (void)Device; +} +static ALvoid NoneUpdate(ALeffectState *State, ALCcontext *Context, const ALeffect *Effect) +{ + (void)State; + (void)Context; + (void)Effect; +} +static ALvoid NoneProcess(ALeffectState *State, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]) +{ + (void)State; + (void)Slot; + (void)SamplesToDo; + (void)SamplesIn; + (void)SamplesOut; +} +ALeffectState *NoneCreate(void) +{ + ALeffectState *state; + + state = calloc(1, sizeof(*state)); + if(!state) + return NULL; + + state->Destroy = NoneDestroy; + state->DeviceUpdate = NoneDeviceUpdate; + state->Update = NoneUpdate; + state->Process = NoneProcess; + + return state; +} + +static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect) +{ + if(EffectSlot->effect.type != (effect?effect->type:AL_EFFECT_NULL)) + { + ALeffectState *NewState = NULL; + if(!effect || effect->type == AL_EFFECT_NULL) + NewState = NoneCreate(); + else if(effect->type == AL_EFFECT_EAXREVERB) + NewState = EAXVerbCreate(); + else if(effect->type == AL_EFFECT_REVERB) + NewState = VerbCreate(); + else if(effect->type == AL_EFFECT_ECHO) + NewState = EchoCreate(); + else if(effect->type == AL_EFFECT_RING_MODULATOR) + NewState = ModulatorCreate(); + /* No new state? An error occured.. */ + if(NewState == NULL || + ALEffect_DeviceUpdate(NewState, Context->Device) == AL_FALSE) + { + if(NewState) + ALEffect_Destroy(NewState); + alSetError(Context, AL_OUT_OF_MEMORY); + return; + } + if(EffectSlot->EffectState) + ALEffect_Destroy(EffectSlot->EffectState); + EffectSlot->EffectState = NewState; + } + if(!effect) + memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect)); + else + memcpy(&EffectSlot->effect, effect, sizeof(*effect)); + ALEffect_Update(EffectSlot->EffectState, Context, effect); +} + + +ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context) +{ + ALsizei pos; + for(pos = 0;pos < Context->EffectSlotMap.size;pos++) + { + ALeffectslot *temp = Context->EffectSlotMap.array[pos].value; + Context->EffectSlotMap.array[pos].value = NULL; + + // Release effectslot structure + ALEffect_Destroy(temp->EffectState); + + ALTHUNK_REMOVEENTRY(temp->effectslot); + memset(temp, 0, sizeof(ALeffectslot)); + free(temp); + } +} diff --git a/project/jni/openal/src/OpenAL32/alBuffer.c b/project/jni/openal/src/OpenAL32/alBuffer.c new file mode 100644 index 000000000..81e17c527 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/alBuffer.c @@ -0,0 +1,1299 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" +#include "alError.h" +#include "alBuffer.h" +#include "alDatabuffer.h" +#include "alThunk.h" + + +static ALenum LoadData(ALbuffer *ALBuf, const ALvoid *data, ALsizei size, ALuint freq, ALenum OrigFormat, ALenum NewFormat); +static void ConvertData(ALfloat *dst, const ALvoid *src, ALint origBytes, ALsizei len); +static void ConvertDataRear(ALfloat *dst, const ALvoid *src, ALint origBytes, ALsizei len); +static void ConvertDataIMA4(ALfloat *dst, const ALvoid *src, ALint origChans, ALsizei len); +static void ConvertDataMULaw(ALfloat *dst, const ALvoid *src, ALsizei len); +static void ConvertDataMULawRear(ALfloat *dst, const ALvoid *src, ALsizei len); + +#define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k))) + +/* +* Global Variables +*/ + +static const long g_IMAStep_size[89]={ // IMA ADPCM Stepsize table + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, + 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, + 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, + 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, + 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442,11487,12635,13899, + 15289,16818,18500,20350,22358,24633,27086,29794,32767 +}; + +static const long g_IMACodeword_4[16]={ // IMA4 ADPCM Codeword decode table + 1, 3, 5, 7, 9, 11, 13, 15, + -1,-3,-5,-7,-9,-11,-13,-15, +}; + +static const long g_IMAIndex_adjust_4[16]={ // IMA4 ADPCM Step index adjust decode table + -1,-1,-1,-1, 2, 4, 6, 8, + -1,-1,-1,-1, 2, 4, 6, 8 +}; + +static const ALshort muLawDecompressionTable[256] = { + -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, + -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, + -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, + -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0 +}; + +/* +* alGenBuffers(ALsizei n, ALuint *puiBuffers) +* +* Generates n AL Buffers, and stores the Buffers Names in the array pointed to by puiBuffers +*/ +AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) +{ + ALCcontext *Context; + ALsizei i=0; + + Context = GetContextSuspended(); + if(!Context) return; + + // Check that we are actually generation some Buffers + if(n > 0) + { + ALCdevice *device = Context->Device; + ALenum err; + + // Check the pointer is valid (and points to enough memory to store Buffer Names) + if(IsBadWritePtr((void*)buffers, n * sizeof(ALuint))) + alSetError(Context, AL_INVALID_VALUE); + else + { + // Create all the new Buffers + while(i < n) + { + ALbuffer *buffer = calloc(1, sizeof(ALbuffer)); + if(!buffer) + { + alSetError(Context, AL_OUT_OF_MEMORY); + alDeleteBuffers(i, buffers); + break; + } + + buffer->buffer = (ALuint)ALTHUNK_ADDENTRY(buffer); + err = InsertUIntMapEntry(&device->BufferMap, buffer->buffer, + buffer); + if(err != AL_NO_ERROR) + { + ALTHUNK_REMOVEENTRY(buffer->buffer); + memset(buffer, 0, sizeof(ALbuffer)); + free(buffer); + + alSetError(Context, err); + alDeleteBuffers(i, buffers); + break; + } + buffers[i++] = buffer->buffer; + } + } + } + + ProcessContext(Context); +} + +/* +* alDeleteBuffers(ALsizei n, ALuint *puiBuffers) +* +* Deletes the n AL Buffers pointed to by puiBuffers +*/ +AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *puiBuffers) +{ + ALCcontext *Context; + ALbuffer *ALBuf; + ALsizei i; + + Context = GetContextSuspended(); + if(!Context) return; + + // Check we are actually Deleting some Buffers + if(n < 0) + alSetError(Context, AL_INVALID_VALUE); + else + { + ALCdevice *device = Context->Device; + ALboolean bFailed = AL_FALSE; + + // Check that all the buffers are valid and can actually be deleted + for (i = 0; i < n; i++) + { + if(!puiBuffers[i]) + continue; + + // Check for valid Buffer ID (can be NULL buffer) + if((ALBuf=LookupBuffer(device->BufferMap, puiBuffers[i])) != NULL) + { + if(ALBuf->refcount != 0) + { + // Buffer still in use, cannot be deleted + alSetError(Context, AL_INVALID_OPERATION); + bFailed = AL_TRUE; + break; + } + } + else + { + // Invalid Buffer + alSetError(Context, AL_INVALID_NAME); + bFailed = AL_TRUE; + break; + } + } + + // If all the Buffers were valid (and have Reference Counts of 0), then we can delete them + if (!bFailed) + { + for (i = 0; i < n; i++) + { + if((ALBuf=LookupBuffer(device->BufferMap, puiBuffers[i])) != NULL) + { + // Release the memory used to store audio data + free(ALBuf->data); + + // Release buffer structure + RemoveUIntMapKey(&device->BufferMap, ALBuf->buffer); + ALTHUNK_REMOVEENTRY(ALBuf->buffer); + + memset(ALBuf, 0, sizeof(ALbuffer)); + free(ALBuf); + } + } + } + } + + ProcessContext(Context); +} + +/* +* alIsBuffer(ALuint uiBuffer) +* +* Checks if ulBuffer is a valid Buffer Name +*/ +AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) +{ + ALCcontext *Context; + ALboolean result; + + Context = GetContextSuspended(); + if(!Context) return AL_FALSE; + + result = ((!buffer || LookupBuffer(Context->Device->BufferMap, buffer)) ? + AL_TRUE : AL_FALSE); + + ProcessContext(Context); + + return result; +} + +/* +* alBufferData(ALuint buffer,ALenum format,ALvoid *data,ALsizei size,ALsizei freq) +* +* Fill buffer with audio data +*/ +AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *data,ALsizei size,ALsizei freq) +{ + ALCcontext *Context; + ALCdevice *device; + ALbuffer *ALBuf; + ALvoid *temp; + ALenum err; + + Context = GetContextSuspended(); + if(!Context) return; + + device = Context->Device; + if((ALBuf=LookupBuffer(device->BufferMap, buffer)) == NULL) + alSetError(Context, AL_INVALID_NAME); /* Invalid Buffer Name */ + else + { + if(Context->SampleSource) + { + ALintptrEXT offset; + + if(Context->SampleSource->state == MAPPED) + { + alSetError(Context, AL_INVALID_OPERATION); + ProcessContext(Context); + return; + } + + offset = (const ALubyte*)data - (ALubyte*)NULL; + data = Context->SampleSource->data + offset; + } + + if(size < 0) + alSetError(Context, AL_INVALID_VALUE); + else if(ALBuf->refcount != 0) + alSetError(Context, AL_INVALID_VALUE); + else + { + switch(format) + { + case AL_FORMAT_MONO8: + case AL_FORMAT_MONO16: + case AL_FORMAT_MONO_FLOAT32: + case AL_FORMAT_MONO_DOUBLE_EXT: + err = LoadData(ALBuf, data, size, freq, format, AL_FORMAT_MONO_FLOAT32); + if(err != AL_NO_ERROR) + alSetError(Context, err); + break; + + case AL_FORMAT_STEREO8: + case AL_FORMAT_STEREO16: + case AL_FORMAT_STEREO_FLOAT32: + case AL_FORMAT_STEREO_DOUBLE_EXT: + err = LoadData(ALBuf, data, size, freq, format, AL_FORMAT_STEREO_FLOAT32); + if(err != AL_NO_ERROR) + alSetError(Context, err); + break; + + case AL_FORMAT_REAR8: + case AL_FORMAT_REAR16: + case AL_FORMAT_REAR32: { + ALenum NewFormat = AL_FORMAT_QUAD32; + ALuint NewChannels = aluChannelsFromFormat(NewFormat); + ALuint NewBytes = aluBytesFromFormat(NewFormat); + ALuint OrigBytes = ((format==AL_FORMAT_REAR8) ? 1 : + ((format==AL_FORMAT_REAR16) ? 2 : + 4)); + ALuint64 newsize, allocsize; + + if((size%(OrigBytes*2)) != 0) + { + alSetError(Context, AL_INVALID_VALUE); + break; + } + + newsize = size / OrigBytes; + newsize *= 2; + + allocsize = (BUFFER_PADDING*NewChannels + newsize)*NewBytes; + if(allocsize > INT_MAX) + { + alSetError(Context, AL_OUT_OF_MEMORY); + break; + } + temp = realloc(ALBuf->data, allocsize); + if(temp) + { + ALBuf->data = temp; + ConvertDataRear(ALBuf->data, data, OrigBytes, newsize); + + ALBuf->format = NewFormat; + ALBuf->eOriginalFormat = format; + ALBuf->size = newsize*NewBytes; + ALBuf->frequency = freq; + + ALBuf->LoopStart = 0; + ALBuf->LoopEnd = newsize / NewChannels; + + ALBuf->OriginalSize = size; + ALBuf->OriginalAlign = OrigBytes * 2; + } + else + alSetError(Context, AL_OUT_OF_MEMORY); + } break; + + case AL_FORMAT_QUAD8_LOKI: + case AL_FORMAT_QUAD16_LOKI: + case AL_FORMAT_QUAD8: + case AL_FORMAT_QUAD16: + case AL_FORMAT_QUAD32: + err = LoadData(ALBuf, data, size, freq, format, AL_FORMAT_QUAD32); + if(err != AL_NO_ERROR) + alSetError(Context, err); + break; + + case AL_FORMAT_51CHN8: + case AL_FORMAT_51CHN16: + case AL_FORMAT_51CHN32: + err = LoadData(ALBuf, data, size, freq, format, AL_FORMAT_51CHN32); + if(err != AL_NO_ERROR) + alSetError(Context, err); + break; + + case AL_FORMAT_61CHN8: + case AL_FORMAT_61CHN16: + case AL_FORMAT_61CHN32: + err = LoadData(ALBuf, data, size, freq, format, AL_FORMAT_61CHN32); + if(err != AL_NO_ERROR) + alSetError(Context, err); + break; + + case AL_FORMAT_71CHN8: + case AL_FORMAT_71CHN16: + case AL_FORMAT_71CHN32: + err = LoadData(ALBuf, data, size, freq, format, AL_FORMAT_71CHN32); + if(err != AL_NO_ERROR) + alSetError(Context, err); + break; + + case AL_FORMAT_MONO_IMA4: + case AL_FORMAT_STEREO_IMA4: { + int Channels = ((format==AL_FORMAT_MONO_IMA4) ? 1 : 2); + ALenum NewFormat = ((Channels==1) ? AL_FORMAT_MONO_FLOAT32 : + AL_FORMAT_STEREO_FLOAT32); + ALuint NewBytes = aluBytesFromFormat(NewFormat); + ALuint64 newsize, allocsize; + + // Here is where things vary: + // nVidia and Apple use 64+1 samples per channel per block => block_size=36*chans bytes + // Most PC sound software uses 2040+1 samples per channel per block -> block_size=1024*chans bytes + if((size%(36*Channels)) != 0) + { + alSetError(Context, AL_INVALID_VALUE); + break; + } + + newsize = size / 36; + newsize *= 65; + + allocsize = (BUFFER_PADDING*Channels + newsize)*NewBytes; + if(allocsize > INT_MAX) + { + alSetError(Context, AL_OUT_OF_MEMORY); + break; + } + temp = realloc(ALBuf->data, allocsize); + if(temp) + { + ALBuf->data = temp; + ConvertDataIMA4(ALBuf->data, data, Channels, newsize/(65*Channels)); + + ALBuf->format = NewFormat; + ALBuf->eOriginalFormat = format; + ALBuf->size = newsize*NewBytes; + ALBuf->frequency = freq; + + ALBuf->LoopStart = 0; + ALBuf->LoopEnd = newsize / Channels; + + ALBuf->OriginalSize = size; + ALBuf->OriginalAlign = 36 * Channels; + } + else + alSetError(Context, AL_OUT_OF_MEMORY); + } break; + + case AL_FORMAT_MONO_MULAW: + case AL_FORMAT_STEREO_MULAW: + case AL_FORMAT_QUAD_MULAW: + case AL_FORMAT_51CHN_MULAW: + case AL_FORMAT_61CHN_MULAW: + case AL_FORMAT_71CHN_MULAW: { + int Channels = ((format==AL_FORMAT_MONO_MULAW) ? 1 : + ((format==AL_FORMAT_STEREO_MULAW) ? 2 : + ((format==AL_FORMAT_QUAD_MULAW) ? 4 : + ((format==AL_FORMAT_51CHN_MULAW) ? 6 : + ((format==AL_FORMAT_61CHN_MULAW) ? 7 : 8))))); + ALenum NewFormat = ((Channels==1) ? AL_FORMAT_MONO_FLOAT32 : + ((Channels==2) ? AL_FORMAT_STEREO_FLOAT32 : + ((Channels==4) ? AL_FORMAT_QUAD32 : + ((Channels==6) ? AL_FORMAT_51CHN32 : + ((Channels==7) ? AL_FORMAT_61CHN32 : + AL_FORMAT_71CHN32))))); + ALuint NewBytes = aluBytesFromFormat(NewFormat); + ALuint64 allocsize; + + if((size%(1*Channels)) != 0) + { + alSetError(Context, AL_INVALID_VALUE); + break; + } + + allocsize = (BUFFER_PADDING*Channels + size)*NewBytes; + if(allocsize > INT_MAX) + { + alSetError(Context, AL_OUT_OF_MEMORY); + break; + } + temp = realloc(ALBuf->data, allocsize); + if(temp) + { + ALBuf->data = temp; + ConvertDataMULaw(ALBuf->data, data, size); + + ALBuf->format = NewFormat; + ALBuf->eOriginalFormat = format; + ALBuf->size = size*NewBytes; + ALBuf->frequency = freq; + + ALBuf->LoopStart = 0; + ALBuf->LoopEnd = size / Channels; + + ALBuf->OriginalSize = size; + ALBuf->OriginalAlign = 1 * Channels; + } + else + alSetError(Context, AL_OUT_OF_MEMORY); + } break; + + case AL_FORMAT_REAR_MULAW: { + ALenum NewFormat = AL_FORMAT_QUAD32; + ALuint NewChannels = aluChannelsFromFormat(NewFormat); + ALuint NewBytes = aluBytesFromFormat(NewFormat); + ALuint64 newsize, allocsize; + + if((size%(1*2)) != 0) + { + alSetError(Context, AL_INVALID_VALUE); + break; + } + + newsize = size * 2; + + allocsize = (BUFFER_PADDING*NewChannels + newsize)*NewBytes; + if(allocsize > INT_MAX) + { + alSetError(Context, AL_OUT_OF_MEMORY); + break; + } + temp = realloc(ALBuf->data, allocsize); + if(temp) + { + ALBuf->data = temp; + ConvertDataMULawRear(ALBuf->data, data, newsize); + + ALBuf->format = NewFormat; + ALBuf->eOriginalFormat = format; + ALBuf->size = newsize*NewBytes; + ALBuf->frequency = freq; + + ALBuf->LoopStart = 0; + ALBuf->LoopEnd = newsize / NewChannels; + + ALBuf->OriginalSize = size; + ALBuf->OriginalAlign = 1 * 2; + } + else + alSetError(Context, AL_OUT_OF_MEMORY); + } break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + } + + ProcessContext(Context); +} + +/* +* alBufferSubDataEXT(ALuint buffer,ALenum format,ALvoid *data,ALsizei offset,ALsizei length) +* +* Fill buffer with audio data +*/ +AL_API ALvoid AL_APIENTRY alBufferSubDataEXT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length) +{ + ALCcontext *Context; + ALCdevice *device; + ALbuffer *ALBuf; + + Context = GetContextSuspended(); + if(!Context) return; + + device = Context->Device; + if((ALBuf=LookupBuffer(device->BufferMap, buffer)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + if(Context->SampleSource) + { + ALintptrEXT offset; + + if(Context->SampleSource->state == MAPPED) + { + alSetError(Context, AL_INVALID_OPERATION); + ProcessContext(Context); + return; + } + + offset = (const ALubyte*)data - (ALubyte*)NULL; + data = Context->SampleSource->data + offset; + } + + if(length < 0 || offset < 0 || (length > 0 && data == NULL)) + alSetError(Context, AL_INVALID_VALUE); + else if(ALBuf->eOriginalFormat != format) + alSetError(Context, AL_INVALID_ENUM); + else if(offset+length < offset || + offset+length > ALBuf->OriginalSize || + (offset%ALBuf->OriginalAlign) != 0 || + (length%ALBuf->OriginalAlign) != 0) + alSetError(Context, AL_INVALID_VALUE); + else + { + switch(format) + { + case AL_FORMAT_MONO8: + case AL_FORMAT_MONO16: + case AL_FORMAT_MONO_FLOAT32: + case AL_FORMAT_MONO_DOUBLE_EXT: + case AL_FORMAT_STEREO8: + case AL_FORMAT_STEREO16: + case AL_FORMAT_STEREO_FLOAT32: + case AL_FORMAT_STEREO_DOUBLE_EXT: + case AL_FORMAT_QUAD8_LOKI: + case AL_FORMAT_QUAD16_LOKI: + case AL_FORMAT_QUAD8: + case AL_FORMAT_QUAD16: + case AL_FORMAT_QUAD32: + case AL_FORMAT_51CHN8: + case AL_FORMAT_51CHN16: + case AL_FORMAT_51CHN32: + case AL_FORMAT_61CHN8: + case AL_FORMAT_61CHN16: + case AL_FORMAT_61CHN32: + case AL_FORMAT_71CHN8: + case AL_FORMAT_71CHN16: + case AL_FORMAT_71CHN32: { + ALuint Bytes = aluBytesFromFormat(format); + + offset /= Bytes; + length /= Bytes; + + ConvertData(&ALBuf->data[offset], data, Bytes, length); + } break; + + case AL_FORMAT_REAR8: + case AL_FORMAT_REAR16: + case AL_FORMAT_REAR32: { + ALuint Bytes = ((format==AL_FORMAT_REAR8) ? 1 : + ((format==AL_FORMAT_REAR16) ? 2 : + 4)); + + offset /= Bytes; + offset *= 2; + length /= Bytes; + length *= 2; + + ConvertDataRear(&ALBuf->data[offset], data, Bytes, length); + } break; + + case AL_FORMAT_MONO_IMA4: + case AL_FORMAT_STEREO_IMA4: { + int Channels = aluChannelsFromFormat(ALBuf->format); + + // offset -> sample*channel offset, length -> block count + offset /= 36; + offset *= 65; + length /= ALBuf->OriginalAlign; + + ConvertDataIMA4(&ALBuf->data[offset], data, Channels, length); + } break; + + case AL_FORMAT_MONO_MULAW: + case AL_FORMAT_STEREO_MULAW: + case AL_FORMAT_QUAD_MULAW: + case AL_FORMAT_51CHN_MULAW: + case AL_FORMAT_61CHN_MULAW: + case AL_FORMAT_71CHN_MULAW: + ConvertDataMULaw(&ALBuf->data[offset], data, length); + break; + + case AL_FORMAT_REAR_MULAW: + offset *= 2; + length *= 2; + ConvertDataMULawRear(&ALBuf->data[offset], data, length); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + } + + ProcessContext(Context); +} + + +AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum eParam, ALfloat flValue) +{ + ALCcontext *pContext; + ALCdevice *device; + + (void)flValue; + + pContext = GetContextSuspended(); + if(!pContext) return; + + device = pContext->Device; + if(LookupBuffer(device->BufferMap, buffer) == NULL) + alSetError(pContext, AL_INVALID_NAME); + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum eParam, ALfloat flValue1, ALfloat flValue2, ALfloat flValue3) +{ + ALCcontext *pContext; + ALCdevice *device; + + (void)flValue1; + (void)flValue2; + (void)flValue3; + + pContext = GetContextSuspended(); + if(!pContext) return; + + device = pContext->Device; + if(LookupBuffer(device->BufferMap, buffer) == NULL) + alSetError(pContext, AL_INVALID_NAME); + else + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum eParam, const ALfloat* flValues) +{ + ALCcontext *pContext; + ALCdevice *device; + + pContext = GetContextSuspended(); + if(!pContext) return; + + device = pContext->Device; + if(!flValues) + alSetError(pContext, AL_INVALID_VALUE); + else if(LookupBuffer(device->BufferMap, buffer) == NULL) + alSetError(pContext, AL_INVALID_NAME); + else + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum eParam, ALint lValue) +{ + ALCcontext *pContext; + ALCdevice *device; + + (void)lValue; + + pContext = GetContextSuspended(); + if(!pContext) return; + + device = pContext->Device; + if(LookupBuffer(device->BufferMap, buffer) == NULL) + alSetError(pContext, AL_INVALID_NAME); + else + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alBuffer3i( ALuint buffer, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3) +{ + ALCcontext *pContext; + ALCdevice *device; + + (void)lValue1; + (void)lValue2; + (void)lValue3; + + pContext = GetContextSuspended(); + if(!pContext) return; + + device = pContext->Device; + if(LookupBuffer(device->BufferMap, buffer) == NULL) + alSetError(pContext, AL_INVALID_NAME); + else + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum eParam, const ALint* plValues) +{ + ALCcontext *pContext; + ALCdevice *device; + ALbuffer *ALBuf; + + pContext = GetContextSuspended(); + if(!pContext) return; + + device = pContext->Device; + if(!plValues) + alSetError(pContext, AL_INVALID_VALUE); + else if((ALBuf=LookupBuffer(device->BufferMap, buffer)) == NULL) + alSetError(pContext, AL_INVALID_NAME); + else + { + switch(eParam) + { + case AL_LOOP_POINTS: + if(ALBuf->refcount > 0) + alSetError(pContext, AL_INVALID_OPERATION); + else if(plValues[0] < 0 || plValues[1] < 0 || + plValues[0] >= plValues[1] || ALBuf->size == 0) + alSetError(pContext, AL_INVALID_VALUE); + else + { + ALint maxlen = ALBuf->size / aluFrameSizeFromFormat(ALBuf->format); + if(plValues[0] > maxlen || plValues[1] > maxlen) + alSetError(pContext, AL_INVALID_VALUE); + else + { + ALBuf->LoopStart = plValues[0]; + ALBuf->LoopEnd = plValues[1]; + } + } + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum eParam, ALfloat *pflValue) +{ + ALCcontext *pContext; + ALCdevice *device; + + pContext = GetContextSuspended(); + if(!pContext) return; + + device = pContext->Device; + if(!pflValue) + alSetError(pContext, AL_INVALID_VALUE); + else if(LookupBuffer(device->BufferMap, buffer) == NULL) + alSetError(pContext, AL_INVALID_NAME); + else + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3) +{ + ALCcontext *pContext; + ALCdevice *device; + + pContext = GetContextSuspended(); + if(!pContext) return; + + device = pContext->Device; + if(!pflValue1 || !pflValue2 || !pflValue3) + alSetError(pContext, AL_INVALID_VALUE); + else if(LookupBuffer(device->BufferMap, buffer) == NULL) + alSetError(pContext, AL_INVALID_NAME); + else + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum eParam, ALfloat* pflValues) +{ + ALCcontext *pContext; + ALCdevice *device; + + pContext = GetContextSuspended(); + if(!pContext) return; + + device = pContext->Device; + if(!pflValues) + alSetError(pContext, AL_INVALID_VALUE); + else if(LookupBuffer(device->BufferMap, buffer) == NULL) + alSetError(pContext, AL_INVALID_NAME); + else + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum eParam, ALint *plValue) +{ + ALCcontext *pContext; + ALbuffer *pBuffer; + ALCdevice *device; + + pContext = GetContextSuspended(); + if(!pContext) return; + + device = pContext->Device; + if(!plValue) + alSetError(pContext, AL_INVALID_VALUE); + else if((pBuffer=LookupBuffer(device->BufferMap, buffer)) == NULL) + alSetError(pContext, AL_INVALID_NAME); + else + { + switch(eParam) + { + case AL_FREQUENCY: + *plValue = pBuffer->frequency; + break; + + case AL_BITS: + *plValue = aluBytesFromFormat(pBuffer->format) * 8; + break; + + case AL_CHANNELS: + *plValue = aluChannelsFromFormat(pBuffer->format); + break; + + case AL_SIZE: + *plValue = pBuffer->size; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3) +{ + ALCcontext *pContext; + ALCdevice *device; + + pContext = GetContextSuspended(); + if(!pContext) return; + + device = pContext->Device; + if(!plValue1 || !plValue2 || !plValue3) + alSetError(pContext, AL_INVALID_VALUE); + else if(LookupBuffer(device->BufferMap, buffer) == NULL) + alSetError(pContext, AL_INVALID_NAME); + else + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum eParam, ALint* plValues) +{ + ALCcontext *pContext; + ALCdevice *device; + ALbuffer *ALBuf; + + pContext = GetContextSuspended(); + if(!pContext) return; + + device = pContext->Device; + if(!plValues) + alSetError(pContext, AL_INVALID_VALUE); + else if((ALBuf=LookupBuffer(device->BufferMap, buffer)) == NULL) + alSetError(pContext, AL_INVALID_NAME); + else + { + switch(eParam) + { + case AL_FREQUENCY: + case AL_BITS: + case AL_CHANNELS: + case AL_SIZE: + alGetBufferi(buffer, eParam, plValues); + break; + + case AL_LOOP_POINTS: + plValues[0] = ALBuf->LoopStart; + plValues[1] = ALBuf->LoopEnd; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + + ProcessContext(pContext); +} + +/* + * LoadData + * + * Loads the specified data into the buffer, using the specified formats. + * Currently, the new format must be 32-bit float, and must have the same + * channel configuration as the original format. This does NOT handle + * compressed formats (eg. IMA4). + */ +static ALenum LoadData(ALbuffer *ALBuf, const ALvoid *data, ALsizei size, ALuint freq, ALenum OrigFormat, ALenum NewFormat) +{ + ALuint NewBytes = aluBytesFromFormat(NewFormat); + ALuint NewChannels = aluChannelsFromFormat(NewFormat); + ALuint OrigBytes = aluBytesFromFormat(OrigFormat); + ALuint OrigChannels = aluChannelsFromFormat(OrigFormat); + ALuint64 newsize, allocsize; + ALvoid *temp; + + assert(NewBytes == 4); + assert(NewChannels == OrigChannels); + + if ((size%(OrigBytes*OrigChannels)) != 0) + return AL_INVALID_VALUE; + + // Allocate extra padding samples + newsize = size / OrigBytes; + allocsize = (BUFFER_PADDING*NewChannels + newsize)*NewBytes; + if(allocsize > INT_MAX) + return AL_OUT_OF_MEMORY; + + temp = realloc(ALBuf->data, allocsize); + if(!temp) return AL_OUT_OF_MEMORY; + ALBuf->data = temp; + + // Samples are converted here + ConvertData(ALBuf->data, data, OrigBytes, newsize); + + ALBuf->format = NewFormat; + ALBuf->eOriginalFormat = OrigFormat; + ALBuf->size = newsize*NewBytes; + ALBuf->frequency = freq; + + ALBuf->LoopStart = 0; + ALBuf->LoopEnd = newsize / NewChannels; + + ALBuf->OriginalSize = size; + ALBuf->OriginalAlign = OrigBytes * OrigChannels; + + return AL_NO_ERROR; +} + +static void ConvertData(ALfloat *dst, const ALvoid *src, ALint origBytes, ALsizei len) +{ + ALsizei i; + ALint smp; + if(src == NULL) + return; + switch(origBytes) + { + case 1: + for(i = 0;i < len;i++) + { + smp = ((ALubyte*)src)[i]; + dst[i] = ((smp < 0x80) ? ((smp-128)/128.0f) : ((smp-128)/127.0f)); + } + break; + + case 2: + for(i = 0;i < len;i++) + { + smp = ((ALshort*)src)[i]; + dst[i] = ((smp < 0) ? (smp/32768.0f) : (smp/32767.0f)); + } + break; + + case 4: + for(i = 0;i < len;i++) + dst[i] = ((ALfloat*)src)[i]; + break; + + case 8: + for(i = 0;i < len;i++) + dst[i] = ((ALdouble*)src)[i]; + break; + + default: + assert(0); + } +} + +static void ConvertDataRear(ALfloat *dst, const ALvoid *src, ALint origBytes, ALsizei len) +{ + ALsizei i; + ALint smp; + if(src == NULL) + return; + switch(origBytes) + { + case 1: + for(i = 0;i < len;i+=4) + { + dst[i+0] = 0; + dst[i+1] = 0; + smp = ((ALubyte*)src)[i/2+0]; + dst[i+2] = ((smp < 0x80) ? ((smp-128)/128.0f) : ((smp-128)/127.0f)); + smp = ((ALubyte*)src)[i/2+1]; + dst[i+3] = ((smp < 0x80) ? ((smp-128)/128.0f) : ((smp-128)/127.0f)); + } + break; + + case 2: + for(i = 0;i < len;i+=4) + { + dst[i+0] = 0; + dst[i+1] = 0; + smp = ((ALshort*)src)[i/2+0]; + dst[i+2] = ((smp < 0) ? (smp/32768.0f) : (smp/32767.0f)); + smp = ((ALshort*)src)[i/2+1]; + dst[i+3] = ((smp < 0) ? (smp/32768.0f) : (smp/32767.0f)); + } + break; + + case 4: + for(i = 0;i < len;i+=4) + { + dst[i+0] = 0; + dst[i+1] = 0; + dst[i+2] = ((ALfloat*)src)[i/2+0]; + dst[i+3] = ((ALfloat*)src)[i/2+1]; + } + break; + + default: + assert(0); + } +} + +static void ConvertDataIMA4(ALfloat *dst, const ALvoid *src, ALint chans, ALsizei len) +{ + const ALubyte *IMAData; + ALint Sample[2],Index[2]; + ALuint IMACode[2]; + ALsizei i,j,k,c; + + if(src == NULL) + return; + + IMAData = src; + for(i = 0;i < len;i++) + { + for(c = 0;c < chans;c++) + { + Sample[c] = *(IMAData++); + Sample[c] |= *(IMAData++) << 8; + Sample[c] = (Sample[c]^0x8000) - 32768; + Index[c] = *(IMAData++); + Index[c] |= *(IMAData++) << 8; + Index[c] = (Index[c]^0x8000) - 32768; + + Index[c] = ((Index[c]<0) ? 0 : Index[c]); + Index[c] = ((Index[c]>88) ? 88 : Index[c]); + + dst[i*65*chans + c] = ((Sample[c] < 0) ? (Sample[c]/32768.0f) : (Sample[c]/32767.0f)); + } + + for(j = 1;j < 65;j += 8) + { + for(c = 0;c < chans;c++) + { + IMACode[c] = *(IMAData++); + IMACode[c] |= *(IMAData++) << 8; + IMACode[c] |= *(IMAData++) << 16; + IMACode[c] |= *(IMAData++) << 24; + } + + for(k = 0;k < 8;k++) + { + for(c = 0;c < chans;c++) + { + Sample[c] += ((g_IMAStep_size[Index[c]]*g_IMACodeword_4[IMACode[c]&15])/8); + Index[c] += g_IMAIndex_adjust_4[IMACode[c]&15]; + + if(Sample[c] < -32768) Sample[c] = -32768; + else if(Sample[c] > 32767) Sample[c] = 32767; + + if(Index[c]<0) Index[c] = 0; + else if(Index[c]>88) Index[c] = 88; + + dst[(i*65+j+k)*chans + c] = ((Sample[c] < 0) ? (Sample[c]/32768.0f) : (Sample[c]/32767.0f)); + IMACode[c] >>= 4; + } + } + } + } +} + +static void ConvertDataMULaw(ALfloat *dst, const ALvoid *src, ALsizei len) +{ + ALsizei i; + ALint smp; + if(src == NULL) + return; + for(i = 0;i < len;i++) + { + smp = muLawDecompressionTable[((ALubyte*)src)[i]]; + dst[i] = ((smp < 0) ? (smp/32768.0f) : (smp/32767.0f)); + } +} + +static void ConvertDataMULawRear(ALfloat *dst, const ALvoid *src, ALsizei len) +{ + ALsizei i; + ALint smp; + if(src == NULL) + return; + for(i = 0;i < len;i+=4) + { + dst[i+0] = 0; + dst[i+1] = 0; + smp = muLawDecompressionTable[((ALubyte*)src)[i/2+0]]; + dst[i+2] = ((smp < 0) ? (smp/32768.0f) : (smp/32767.0f)); + smp = muLawDecompressionTable[((ALubyte*)src)[i/2+1]]; + dst[i+3] = ((smp < 0) ? (smp/32768.0f) : (smp/32767.0f)); + } +} + +/* +* ReleaseALBuffers() +* +* INTERNAL FN : Called by DLLMain on exit to destroy any buffers that still exist +*/ +ALvoid ReleaseALBuffers(ALCdevice *device) +{ + ALsizei i; + for(i = 0;i < device->BufferMap.size;i++) + { + ALbuffer *temp = device->BufferMap.array[i].value; + device->BufferMap.array[i].value = NULL; + + // Release sample data + free(temp->data); + + // Release Buffer structure + ALTHUNK_REMOVEENTRY(temp->buffer); + memset(temp, 0, sizeof(ALbuffer)); + free(temp); + } +} diff --git a/project/jni/openal/src/OpenAL32/alDatabuffer.c b/project/jni/openal/src/OpenAL32/alDatabuffer.c new file mode 100644 index 000000000..b799f1337 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/alDatabuffer.c @@ -0,0 +1,656 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" +#include "alError.h" +#include "alDatabuffer.h" +#include "alThunk.h" + + +#define LookupDatabuffer(m, k) ((ALdatabuffer*)LookupUIntMapKey(&(m), (k))) + +/* +* alGenDatabuffersEXT(ALsizei n, ALuint *puiBuffers) +* +* Generates n AL Databuffers, and stores the Databuffers Names in the array pointed to by puiBuffers +*/ +AL_API ALvoid AL_APIENTRY alGenDatabuffersEXT(ALsizei n,ALuint *puiBuffers) +{ + ALCcontext *Context; + ALsizei i=0; + + Context = GetContextSuspended(); + if(!Context) return; + + /* Check that we are actually generation some Databuffers */ + if(n > 0) + { + ALCdevice *device = Context->Device; + + /* Check the pointer is valid (and points to enough memory to store + * Databuffer Names) */ + if(!IsBadWritePtr((void*)puiBuffers, n * sizeof(ALuint))) + { + ALenum err; + + /* Create all the new Databuffers */ + while(i < n) + { + ALdatabuffer *buffer = calloc(1, sizeof(ALdatabuffer)); + if(!buffer) + { + alSetError(Context, AL_OUT_OF_MEMORY); + alDeleteDatabuffersEXT(i, puiBuffers); + break; + } + + buffer->databuffer = ALTHUNK_ADDENTRY(buffer); + err = InsertUIntMapEntry(&device->DatabufferMap, + buffer->databuffer, buffer); + if(err != AL_NO_ERROR) + { + ALTHUNK_REMOVEENTRY(buffer->databuffer); + memset(buffer, 0, sizeof(ALdatabuffer)); + free(buffer); + + alSetError(Context, err); + alDeleteDatabuffersEXT(i, puiBuffers); + break; + } + puiBuffers[i++] = buffer->databuffer; + + buffer->state = UNMAPPED; + } + } + else + alSetError(Context, AL_INVALID_VALUE); + } + + ProcessContext(Context); +} + +/* +* alDatabeleteBuffersEXT(ALsizei n, ALuint *puiBuffers) +* +* Deletes the n AL Databuffers pointed to by puiBuffers +*/ +AL_API ALvoid AL_APIENTRY alDeleteDatabuffersEXT(ALsizei n, const ALuint *puiBuffers) +{ + ALCcontext *Context; + ALdatabuffer *ALBuf; + ALsizei i; + ALboolean bFailed = AL_FALSE; + + Context = GetContextSuspended(); + if(!Context) return; + + /* Check we are actually Deleting some Databuffers */ + if(n >= 0) + { + ALCdevice *device = Context->Device; + + /* Check that all the databuffers are valid and can actually be + * deleted */ + for(i = 0;i < n;i++) + { + if(!puiBuffers[i]) + continue; + + /* Check for valid Buffer ID */ + if((ALBuf=LookupDatabuffer(device->DatabufferMap, puiBuffers[i])) != NULL) + { + if(ALBuf->state != UNMAPPED) + { + /* Databuffer still in use, cannot be deleted */ + alSetError(Context, AL_INVALID_OPERATION); + bFailed = AL_TRUE; + break; + } + } + else + { + /* Invalid Databuffer */ + alSetError(Context, AL_INVALID_NAME); + bFailed = AL_TRUE; + break; + } + } + + /* If all the Databuffers were valid (and unmapped), then we can + * delete them */ + if(!bFailed) + { + for(i = 0;i < n;i++) + { + if((ALBuf=LookupDatabuffer(device->DatabufferMap, puiBuffers[i])) != NULL) + { + if(ALBuf == Context->SampleSource) + Context->SampleSource = NULL; + if(ALBuf == Context->SampleSink) + Context->SampleSink = NULL; + + // Release the memory used to store audio data + free(ALBuf->data); + + // Release buffer structure + RemoveUIntMapKey(&device->DatabufferMap, ALBuf->databuffer); + ALTHUNK_REMOVEENTRY(puiBuffers[i]); + + memset(ALBuf, 0, sizeof(ALdatabuffer)); + free(ALBuf); + } + } + } + } + else + alSetError(Context, AL_INVALID_VALUE); + + ProcessContext(Context); +} + +/* +* alIsDatabufferEXT(ALuint uiBuffer) +* +* Checks if ulBuffer is a valid Databuffer Name +*/ +AL_API ALboolean AL_APIENTRY alIsDatabufferEXT(ALuint buffer) +{ + ALCcontext *Context; + ALboolean result; + ALCdevice *device; + + Context = GetContextSuspended(); + if(!Context) return AL_FALSE; + + device = Context->Device; + result = ((!buffer || LookupDatabuffer(device->DatabufferMap, buffer)) ? + AL_TRUE : AL_FALSE); + + ProcessContext(Context); + + return result; +} + +/* +* alDatabufferDataEXT(ALuint buffer,ALvoid *data,ALsizei size,ALenum usage) +* +* Fill databuffer with data +*/ +AL_API ALvoid AL_APIENTRY alDatabufferDataEXT(ALuint buffer,const ALvoid *data,ALsizeiptrEXT size,ALenum usage) +{ + ALCcontext *Context; + ALdatabuffer *ALBuf; + ALCdevice *Device; + ALvoid *temp; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if((ALBuf=LookupDatabuffer(Device->DatabufferMap, buffer)) != NULL) + { + if(ALBuf->state == UNMAPPED) + { + if(usage == AL_STREAM_WRITE_EXT || usage == AL_STREAM_READ_EXT || + usage == AL_STREAM_COPY_EXT || usage == AL_STATIC_WRITE_EXT || + usage == AL_STATIC_READ_EXT || usage == AL_STATIC_COPY_EXT || + usage == AL_DYNAMIC_WRITE_EXT || usage == AL_DYNAMIC_READ_EXT || + usage == AL_DYNAMIC_COPY_EXT) + { + if(size >= 0) + { + /* (Re)allocate data */ + temp = realloc(ALBuf->data, size); + if(temp) + { + ALBuf->data = temp; + ALBuf->size = size; + ALBuf->usage = usage; + if(data) + memcpy(ALBuf->data, data, size); + } + else + alSetError(Context, AL_OUT_OF_MEMORY); + } + else + alSetError(Context, AL_INVALID_VALUE); + } + else + alSetError(Context, AL_INVALID_ENUM); + } + else + alSetError(Context, AL_INVALID_OPERATION); + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alDatabufferSubDataEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, const ALvoid *data) +{ + ALCcontext *pContext; + ALdatabuffer *pBuffer; + ALCdevice *Device; + + pContext = GetContextSuspended(); + if(!pContext) return; + + Device = pContext->Device; + if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL) + { + if(start >= 0 && length >= 0 && start+length <= pBuffer->size) + { + if(pBuffer->state == UNMAPPED) + memcpy(pBuffer->data+start, data, length); + else + alSetError(pContext, AL_INVALID_OPERATION); + } + else + alSetError(pContext, AL_INVALID_VALUE); + } + else + alSetError(pContext, AL_INVALID_NAME); + + ProcessContext(pContext); +} + +AL_API ALvoid AL_APIENTRY alGetDatabufferSubDataEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, ALvoid *data) +{ + ALCcontext *pContext; + ALdatabuffer *pBuffer; + ALCdevice *Device; + + pContext = GetContextSuspended(); + if(!pContext) return; + + Device = pContext->Device; + if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL) + { + if(start >= 0 && length >= 0 && start+length <= pBuffer->size) + { + if(pBuffer->state == UNMAPPED) + memcpy(data, pBuffer->data+start, length); + else + alSetError(pContext, AL_INVALID_OPERATION); + } + else + alSetError(pContext, AL_INVALID_VALUE); + } + else + alSetError(pContext, AL_INVALID_NAME); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat flValue) +{ + ALCcontext *pContext; + ALCdevice *Device; + + (void)flValue; + + pContext = GetContextSuspended(); + if(!pContext) return; + + Device = pContext->Device; + if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL) + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + + ProcessContext(pContext); +} + +AL_API ALvoid AL_APIENTRY alDatabufferfvEXT(ALuint buffer, ALenum eParam, const ALfloat* flValues) +{ + ALCcontext *pContext; + ALCdevice *Device; + + (void)flValues; + + pContext = GetContextSuspended(); + if(!pContext) return; + + Device = pContext->Device; + if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL) + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alDatabufferiEXT(ALuint buffer, ALenum eParam, ALint lValue) +{ + ALCcontext *pContext; + ALCdevice *Device; + + (void)lValue; + + pContext = GetContextSuspended(); + if(!pContext) return; + + Device = pContext->Device; + if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL) + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + + ProcessContext(pContext); +} + +AL_API ALvoid AL_APIENTRY alDatabufferivEXT(ALuint buffer, ALenum eParam, const ALint* plValues) +{ + ALCcontext *pContext; + ALCdevice *Device; + + (void)plValues; + + pContext = GetContextSuspended(); + if(!pContext) return; + + Device = pContext->Device; + if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL) + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alGetDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat *pflValue) +{ + ALCcontext *pContext; + ALCdevice *Device; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(pflValue) + { + Device = pContext->Device; + if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL) + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + +AL_API ALvoid AL_APIENTRY alGetDatabufferfvEXT(ALuint buffer, ALenum eParam, ALfloat* pflValues) +{ + ALCcontext *pContext; + ALCdevice *Device; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(pflValues) + { + Device = pContext->Device; + if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL) + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + +AL_API ALvoid AL_APIENTRY alGetDatabufferiEXT(ALuint buffer, ALenum eParam, ALint *plValue) +{ + ALCcontext *pContext; + ALdatabuffer *pBuffer; + ALCdevice *Device; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(plValue) + { + Device = pContext->Device; + if((pBuffer=LookupDatabuffer(Device->DatabufferMap, buffer)) != NULL) + { + switch(eParam) + { + case AL_SIZE: + *plValue = (ALint)pBuffer->size; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + +AL_API ALvoid AL_APIENTRY alGetDatabufferivEXT(ALuint buffer, ALenum eParam, ALint* plValues) +{ + ALCcontext *pContext; + ALCdevice *Device; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(plValues) + { + Device = pContext->Device; + if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL) + { + switch (eParam) + { + case AL_SIZE: + alGetDatabufferiEXT(buffer, eParam, plValues); + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alSelectDatabufferEXT(ALenum target, ALuint uiBuffer) +{ + ALCcontext *pContext; + ALdatabuffer *pBuffer = NULL; + ALCdevice *Device; + + pContext = GetContextSuspended(); + if(!pContext) return; + + Device = pContext->Device; + if(uiBuffer == 0 || + (pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL) + { + if(target == AL_SAMPLE_SOURCE_EXT) + pContext->SampleSource = pBuffer; + else if(target == AL_SAMPLE_SINK_EXT) + pContext->SampleSink = pBuffer; + else + alSetError(pContext, AL_INVALID_VALUE); + } + else + alSetError(pContext, AL_INVALID_NAME); + + ProcessContext(pContext); +} + + +AL_API ALvoid* AL_APIENTRY alMapDatabufferEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, ALenum access) +{ + ALCcontext *pContext; + ALdatabuffer *pBuffer; + ALvoid *ret = NULL; + ALCdevice *Device; + + pContext = GetContextSuspended(); + if(!pContext) return NULL; + + Device = pContext->Device; + if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL) + { + if(start >= 0 && length >= 0 && start+length <= pBuffer->size) + { + if(access == AL_READ_ONLY_EXT || access == AL_WRITE_ONLY_EXT || + access == AL_READ_WRITE_EXT) + { + if(pBuffer->state == UNMAPPED) + { + ret = pBuffer->data + start; + pBuffer->state = MAPPED; + } + else + alSetError(pContext, AL_INVALID_OPERATION); + } + else + alSetError(pContext, AL_INVALID_ENUM); + } + else + alSetError(pContext, AL_INVALID_VALUE); + } + else + alSetError(pContext, AL_INVALID_NAME); + + ProcessContext(pContext); + + return ret; +} + +AL_API ALvoid AL_APIENTRY alUnmapDatabufferEXT(ALuint uiBuffer) +{ + ALCcontext *pContext; + ALdatabuffer *pBuffer; + ALCdevice *Device; + + pContext = GetContextSuspended(); + if(!pContext) return; + + Device = pContext->Device; + if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL) + { + if(pBuffer->state == MAPPED) + pBuffer->state = UNMAPPED; + else + alSetError(pContext, AL_INVALID_OPERATION); + } + else + alSetError(pContext, AL_INVALID_NAME); + + ProcessContext(pContext); +} + + +/* +* ReleaseALDatabuffers() +* +* INTERNAL FN : Called by DLLMain on exit to destroy any buffers that still exist +*/ +ALvoid ReleaseALDatabuffers(ALCdevice *device) +{ + ALsizei i; + for(i = 0;i < device->DatabufferMap.size;i++) + { + ALdatabuffer *temp = device->DatabufferMap.array[i].value; + device->DatabufferMap.array[i].value = NULL; + + // Release buffer data + free(temp->data); + + // Release Buffer structure + ALTHUNK_REMOVEENTRY(temp->databuffer); + memset(temp, 0, sizeof(ALdatabuffer)); + free(temp); + } +} diff --git a/project/jni/openal/src/OpenAL32/alEffect.c b/project/jni/openal/src/OpenAL32/alEffect.c new file mode 100644 index 000000000..f3109ca22 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/alEffect.c @@ -0,0 +1,1376 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alEffect.h" +#include "alThunk.h" +#include "alError.h" + + +ALboolean DisabledEffects[MAX_EFFECTS]; + + +static void InitEffectParams(ALeffect *effect, ALenum type); + +#define LookupEffect(m, k) ((ALeffect*)LookupUIntMapKey(&(m), (k))) + +AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) +{ + ALCcontext *Context; + ALsizei i=0; + + Context = GetContextSuspended(); + if(!Context) return; + + if (n > 0) + { + ALCdevice *device = Context->Device; + + // Check that enough memory has been allocted in the 'effects' array for n Effects + if (!IsBadWritePtr((void*)effects, n * sizeof(ALuint))) + { + ALenum err; + + while(i < n) + { + ALeffect *effect = calloc(1, sizeof(ALeffect)); + if(!effect) + { + alSetError(Context, AL_OUT_OF_MEMORY); + alDeleteEffects(i, effects); + break; + } + + effect->effect = ALTHUNK_ADDENTRY(effect); + err = InsertUIntMapEntry(&device->EffectMap, effect->effect, + effect); + if(err != AL_NO_ERROR) + { + ALTHUNK_REMOVEENTRY(effect->effect); + memset(effect, 0, sizeof(ALeffect)); + free(effect); + + alSetError(Context, err); + alDeleteEffects(i, effects); + break; + } + + effects[i++] = effect->effect; + InitEffectParams(effect, AL_EFFECT_NULL); + } + } + } + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects) +{ + ALCcontext *Context; + ALeffect *ALEffect; + ALsizei i; + + Context = GetContextSuspended(); + if(!Context) return; + + if (n >= 0) + { + ALCdevice *device = Context->Device; + + // Check that all effects are valid + for (i = 0; i < n; i++) + { + if(!effects[i]) + continue; + + if(!LookupEffect(device->EffectMap, effects[i])) + { + alSetError(Context, AL_INVALID_NAME); + break; + } + } + + if (i == n) + { + // All effects are valid + for (i = 0; i < n; i++) + { + // Recheck that the effect is valid, because there could be duplicated names + if((ALEffect=LookupEffect(device->EffectMap, effects[i])) != NULL) + { + RemoveUIntMapKey(&device->EffectMap, ALEffect->effect); + ALTHUNK_REMOVEENTRY(ALEffect->effect); + + memset(ALEffect, 0, sizeof(ALeffect)); + free(ALEffect); + } + } + } + } + else + alSetError(Context, AL_INVALID_VALUE); + + ProcessContext(Context); +} + +AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) +{ + ALCcontext *Context; + ALboolean result; + + Context = GetContextSuspended(); + if(!Context) return AL_FALSE; + + result = ((!effect || LookupEffect(Context->Device->EffectMap, effect)) ? + AL_TRUE : AL_FALSE); + + ProcessContext(Context); + + return result; +} + +AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL) + { + if(param == AL_EFFECT_TYPE) + { + ALboolean isOk = (iValue == AL_EFFECT_NULL || + (iValue == AL_EFFECT_EAXREVERB && !DisabledEffects[EAXREVERB]) || + (iValue == AL_EFFECT_REVERB && !DisabledEffects[REVERB]) || + (iValue == AL_EFFECT_ECHO && !DisabledEffects[ECHO]) || + (iValue == AL_EFFECT_RING_MODULATOR && !DisabledEffects[MODULATOR])); + + if(isOk) + InitEffectParams(ALEffect, iValue); + else + alSetError(Context, AL_INVALID_VALUE); + } + else if(ALEffect->type == AL_EFFECT_EAXREVERB) + { + switch(param) + { + case AL_EAXREVERB_DECAY_HFLIMIT: + if(iValue >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && + iValue <= AL_EAXREVERB_MAX_DECAY_HFLIMIT) + ALEffect->Reverb.DecayHFLimit = iValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_REVERB) + { + switch(param) + { + case AL_REVERB_DECAY_HFLIMIT: + if(iValue >= AL_REVERB_MIN_DECAY_HFLIMIT && + iValue <= AL_REVERB_MAX_DECAY_HFLIMIT) + ALEffect->Reverb.DecayHFLimit = iValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_ECHO) + { + switch(param) + { + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_RING_MODULATOR) + { + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + alEffectf(effect, param, (ALfloat)iValue); + break; + + case AL_RING_MODULATOR_WAVEFORM: + if(iValue >= AL_RING_MODULATOR_MIN_WAVEFORM && + iValue <= AL_RING_MODULATOR_MAX_WAVEFORM) + ALEffect->Modulator.Waveform = iValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_ENUM); + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL) + { + if(param == AL_EFFECT_TYPE) + { + alEffecti(effect, param, piValues[0]); + } + else if(ALEffect->type == AL_EFFECT_EAXREVERB) + { + switch(param) + { + case AL_EAXREVERB_DECAY_HFLIMIT: + alEffecti(effect, param, piValues[0]); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_REVERB) + { + switch(param) + { + case AL_REVERB_DECAY_HFLIMIT: + alEffecti(effect, param, piValues[0]); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_ECHO) + { + switch(param) + { + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_RING_MODULATOR) + { + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + case AL_RING_MODULATOR_WAVEFORM: + alEffecti(effect, param, piValues[0]); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_ENUM); + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL) + { + if(ALEffect->type == AL_EFFECT_EAXREVERB) + { + switch(param) + { + case AL_EAXREVERB_DENSITY: + if(flValue >= AL_EAXREVERB_MIN_DENSITY && + flValue <= AL_EAXREVERB_MAX_DENSITY) + ALEffect->Reverb.Density = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_DIFFUSION: + if(flValue >= AL_EAXREVERB_MIN_DIFFUSION && + flValue <= AL_EAXREVERB_MAX_DIFFUSION) + ALEffect->Reverb.Diffusion = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_GAIN: + if(flValue >= AL_EAXREVERB_MIN_GAIN && + flValue <= AL_EAXREVERB_MAX_GAIN) + ALEffect->Reverb.Gain = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_GAINHF: + if(flValue >= AL_EAXREVERB_MIN_GAINHF && + flValue <= AL_EAXREVERB_MAX_GAIN) + ALEffect->Reverb.GainHF = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_GAINLF: + if(flValue >= AL_EAXREVERB_MIN_GAINLF && + flValue <= AL_EAXREVERB_MAX_GAINLF) + ALEffect->Reverb.GainLF = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_DECAY_TIME: + if(flValue >= AL_EAXREVERB_MIN_DECAY_TIME && + flValue <= AL_EAXREVERB_MAX_DECAY_TIME) + ALEffect->Reverb.DecayTime = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_DECAY_HFRATIO: + if(flValue >= AL_EAXREVERB_MIN_DECAY_HFRATIO && + flValue <= AL_EAXREVERB_MAX_DECAY_HFRATIO) + ALEffect->Reverb.DecayHFRatio = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_DECAY_LFRATIO: + if(flValue >= AL_EAXREVERB_MIN_DECAY_LFRATIO && + flValue <= AL_EAXREVERB_MAX_DECAY_LFRATIO) + ALEffect->Reverb.DecayLFRatio = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_REFLECTIONS_GAIN: + if(flValue >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && + flValue <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN) + ALEffect->Reverb.ReflectionsGain = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_REFLECTIONS_DELAY: + if(flValue >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && + flValue <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY) + ALEffect->Reverb.ReflectionsDelay = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_LATE_REVERB_GAIN: + if(flValue >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && + flValue <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN) + ALEffect->Reverb.LateReverbGain = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_LATE_REVERB_DELAY: + if(flValue >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && + flValue <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY) + ALEffect->Reverb.LateReverbDelay = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: + if(flValue >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && + flValue <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF) + ALEffect->Reverb.AirAbsorptionGainHF = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_ECHO_TIME: + if(flValue >= AL_EAXREVERB_MIN_ECHO_TIME && + flValue <= AL_EAXREVERB_MAX_ECHO_TIME) + ALEffect->Reverb.EchoTime = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_ECHO_DEPTH: + if(flValue >= AL_EAXREVERB_MIN_ECHO_DEPTH && + flValue <= AL_EAXREVERB_MAX_ECHO_DEPTH) + ALEffect->Reverb.EchoDepth = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_MODULATION_TIME: + if(flValue >= AL_EAXREVERB_MIN_MODULATION_TIME && + flValue <= AL_EAXREVERB_MAX_MODULATION_TIME) + ALEffect->Reverb.ModulationTime = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_MODULATION_DEPTH: + if(flValue >= AL_EAXREVERB_MIN_MODULATION_DEPTH && + flValue <= AL_EAXREVERB_MAX_MODULATION_DEPTH) + ALEffect->Reverb.ModulationDepth = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_HFREFERENCE: + if(flValue >= AL_EAXREVERB_MIN_HFREFERENCE && + flValue <= AL_EAXREVERB_MAX_HFREFERENCE) + ALEffect->Reverb.HFReference = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_LFREFERENCE: + if(flValue >= AL_EAXREVERB_MIN_LFREFERENCE && + flValue <= AL_EAXREVERB_MAX_LFREFERENCE) + ALEffect->Reverb.LFReference = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: + if(flValue >= 0.0f && flValue <= 10.0f) + ALEffect->Reverb.RoomRolloffFactor = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_REVERB) + { + switch(param) + { + case AL_REVERB_DENSITY: + if(flValue >= AL_REVERB_MIN_DENSITY && + flValue <= AL_REVERB_MAX_DENSITY) + ALEffect->Reverb.Density = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_REVERB_DIFFUSION: + if(flValue >= AL_REVERB_MIN_DIFFUSION && + flValue <= AL_REVERB_MAX_DIFFUSION) + ALEffect->Reverb.Diffusion = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_REVERB_GAIN: + if(flValue >= AL_REVERB_MIN_GAIN && + flValue <= AL_REVERB_MAX_GAIN) + ALEffect->Reverb.Gain = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_REVERB_GAINHF: + if(flValue >= AL_REVERB_MIN_GAINHF && + flValue <= AL_REVERB_MAX_GAINHF) + ALEffect->Reverb.GainHF = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_REVERB_DECAY_TIME: + if(flValue >= AL_REVERB_MIN_DECAY_TIME && + flValue <= AL_REVERB_MAX_DECAY_TIME) + ALEffect->Reverb.DecayTime = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_REVERB_DECAY_HFRATIO: + if(flValue >= AL_REVERB_MIN_DECAY_HFRATIO && + flValue <= AL_REVERB_MAX_DECAY_HFRATIO) + ALEffect->Reverb.DecayHFRatio = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_REVERB_REFLECTIONS_GAIN: + if(flValue >= AL_REVERB_MIN_REFLECTIONS_GAIN && + flValue <= AL_REVERB_MAX_REFLECTIONS_GAIN) + ALEffect->Reverb.ReflectionsGain = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_REVERB_REFLECTIONS_DELAY: + if(flValue >= AL_REVERB_MIN_REFLECTIONS_DELAY && + flValue <= AL_REVERB_MAX_REFLECTIONS_DELAY) + ALEffect->Reverb.ReflectionsDelay = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_REVERB_LATE_REVERB_GAIN: + if(flValue >= AL_REVERB_MIN_LATE_REVERB_GAIN && + flValue <= AL_REVERB_MAX_LATE_REVERB_GAIN) + ALEffect->Reverb.LateReverbGain = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_REVERB_LATE_REVERB_DELAY: + if(flValue >= AL_REVERB_MIN_LATE_REVERB_DELAY && + flValue <= AL_REVERB_MAX_LATE_REVERB_DELAY) + ALEffect->Reverb.LateReverbDelay = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_REVERB_AIR_ABSORPTION_GAINHF: + if(flValue >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && + flValue <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF) + ALEffect->Reverb.AirAbsorptionGainHF = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_REVERB_ROOM_ROLLOFF_FACTOR: + if(flValue >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && + flValue <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR) + ALEffect->Reverb.RoomRolloffFactor = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_ECHO) + { + switch(param) + { + case AL_ECHO_DELAY: + if(flValue >= AL_ECHO_MIN_DELAY && flValue <= AL_ECHO_MAX_DELAY) + ALEffect->Echo.Delay = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_ECHO_LRDELAY: + if(flValue >= AL_ECHO_MIN_LRDELAY && flValue <= AL_ECHO_MAX_LRDELAY) + ALEffect->Echo.LRDelay = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_ECHO_DAMPING: + if(flValue >= AL_ECHO_MIN_DAMPING && flValue <= AL_ECHO_MAX_DAMPING) + ALEffect->Echo.Damping = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_ECHO_FEEDBACK: + if(flValue >= AL_ECHO_MIN_FEEDBACK && flValue <= AL_ECHO_MAX_FEEDBACK) + ALEffect->Echo.Feedback = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_ECHO_SPREAD: + if(flValue >= AL_ECHO_MIN_SPREAD && flValue <= AL_ECHO_MAX_SPREAD) + ALEffect->Echo.Spread = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_RING_MODULATOR) + { + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + if(flValue >= AL_RING_MODULATOR_MIN_FREQUENCY && + flValue <= AL_RING_MODULATOR_MAX_FREQUENCY) + ALEffect->Modulator.Frequency = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + if(flValue >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && + flValue <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF) + ALEffect->Modulator.HighPassCutoff = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_ENUM); + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL) + { + if(ALEffect->type == AL_EFFECT_EAXREVERB) + { + switch(param) + { + case AL_EAXREVERB_DENSITY: + case AL_EAXREVERB_DIFFUSION: + case AL_EAXREVERB_GAIN: + case AL_EAXREVERB_GAINHF: + case AL_EAXREVERB_GAINLF: + case AL_EAXREVERB_DECAY_TIME: + case AL_EAXREVERB_DECAY_HFRATIO: + case AL_EAXREVERB_DECAY_LFRATIO: + case AL_EAXREVERB_REFLECTIONS_GAIN: + case AL_EAXREVERB_REFLECTIONS_DELAY: + case AL_EAXREVERB_LATE_REVERB_GAIN: + case AL_EAXREVERB_LATE_REVERB_DELAY: + case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: + case AL_EAXREVERB_ECHO_TIME: + case AL_EAXREVERB_ECHO_DEPTH: + case AL_EAXREVERB_MODULATION_TIME: + case AL_EAXREVERB_MODULATION_DEPTH: + case AL_EAXREVERB_HFREFERENCE: + case AL_EAXREVERB_LFREFERENCE: + case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: + alEffectf(effect, param, pflValues[0]); + break; + + case AL_EAXREVERB_REFLECTIONS_PAN: + if(!isnan(pflValues[0]) && !isnan(pflValues[1]) && !isnan(pflValues[2])) + { + ALEffect->Reverb.ReflectionsPan[0] = pflValues[0]; + ALEffect->Reverb.ReflectionsPan[1] = pflValues[1]; + ALEffect->Reverb.ReflectionsPan[2] = pflValues[2]; + } + else + alSetError(Context, AL_INVALID_VALUE); + break; + case AL_EAXREVERB_LATE_REVERB_PAN: + if(!isnan(pflValues[0]) && !isnan(pflValues[1]) && !isnan(pflValues[2])) + { + ALEffect->Reverb.LateReverbPan[0] = pflValues[0]; + ALEffect->Reverb.LateReverbPan[1] = pflValues[1]; + ALEffect->Reverb.LateReverbPan[2] = pflValues[2]; + } + else + alSetError(Context, AL_INVALID_VALUE); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_REVERB) + { + switch(param) + { + case AL_REVERB_DENSITY: + case AL_REVERB_DIFFUSION: + case AL_REVERB_GAIN: + case AL_REVERB_GAINHF: + case AL_REVERB_DECAY_TIME: + case AL_REVERB_DECAY_HFRATIO: + case AL_REVERB_REFLECTIONS_GAIN: + case AL_REVERB_REFLECTIONS_DELAY: + case AL_REVERB_LATE_REVERB_GAIN: + case AL_REVERB_LATE_REVERB_DELAY: + case AL_REVERB_AIR_ABSORPTION_GAINHF: + case AL_REVERB_ROOM_ROLLOFF_FACTOR: + alEffectf(effect, param, pflValues[0]); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_ECHO) + { + switch(param) + { + case AL_ECHO_DELAY: + case AL_ECHO_LRDELAY: + case AL_ECHO_DAMPING: + case AL_ECHO_FEEDBACK: + case AL_ECHO_SPREAD: + alEffectf(effect, param, pflValues[0]); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_RING_MODULATOR) + { + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + alEffectf(effect, param, pflValues[0]); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_ENUM); + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL) + { + if(param == AL_EFFECT_TYPE) + { + *piValue = ALEffect->type; + } + else if(ALEffect->type == AL_EFFECT_EAXREVERB) + { + switch(param) + { + case AL_EAXREVERB_DECAY_HFLIMIT: + *piValue = ALEffect->Reverb.DecayHFLimit; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_REVERB) + { + switch(param) + { + case AL_REVERB_DECAY_HFLIMIT: + *piValue = ALEffect->Reverb.DecayHFLimit; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_ECHO) + { + switch(param) + { + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_RING_MODULATOR) + { + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + *piValue = (ALint)ALEffect->Modulator.Frequency; + break; + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + *piValue = (ALint)ALEffect->Modulator.HighPassCutoff; + break; + case AL_RING_MODULATOR_WAVEFORM: + *piValue = ALEffect->Modulator.Waveform; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_ENUM); + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL) + { + if(param == AL_EFFECT_TYPE) + { + alGetEffecti(effect, param, piValues); + } + else if(ALEffect->type == AL_EFFECT_EAXREVERB) + { + switch(param) + { + case AL_EAXREVERB_DECAY_HFLIMIT: + alGetEffecti(effect, param, piValues); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_REVERB) + { + switch(param) + { + case AL_REVERB_DECAY_HFLIMIT: + alGetEffecti(effect, param, piValues); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_ECHO) + { + switch(param) + { + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_RING_MODULATOR) + { + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + case AL_RING_MODULATOR_WAVEFORM: + alGetEffecti(effect, param, piValues); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_ENUM); + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL) + { + if(ALEffect->type == AL_EFFECT_EAXREVERB) + { + switch(param) + { + case AL_EAXREVERB_DENSITY: + *pflValue = ALEffect->Reverb.Density; + break; + + case AL_EAXREVERB_DIFFUSION: + *pflValue = ALEffect->Reverb.Diffusion; + break; + + case AL_EAXREVERB_GAIN: + *pflValue = ALEffect->Reverb.Gain; + break; + + case AL_EAXREVERB_GAINHF: + *pflValue = ALEffect->Reverb.GainHF; + break; + + case AL_EAXREVERB_GAINLF: + *pflValue = ALEffect->Reverb.GainLF; + break; + + case AL_EAXREVERB_DECAY_TIME: + *pflValue = ALEffect->Reverb.DecayTime; + break; + + case AL_EAXREVERB_DECAY_HFRATIO: + *pflValue = ALEffect->Reverb.DecayHFRatio; + break; + + case AL_EAXREVERB_DECAY_LFRATIO: + *pflValue = ALEffect->Reverb.DecayLFRatio; + break; + + case AL_EAXREVERB_REFLECTIONS_GAIN: + *pflValue = ALEffect->Reverb.ReflectionsGain; + break; + + case AL_EAXREVERB_REFLECTIONS_DELAY: + *pflValue = ALEffect->Reverb.ReflectionsDelay; + break; + + case AL_EAXREVERB_LATE_REVERB_GAIN: + *pflValue = ALEffect->Reverb.LateReverbGain; + break; + + case AL_EAXREVERB_LATE_REVERB_DELAY: + *pflValue = ALEffect->Reverb.LateReverbDelay; + break; + + case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: + *pflValue = ALEffect->Reverb.AirAbsorptionGainHF; + break; + + case AL_EAXREVERB_ECHO_TIME: + *pflValue = ALEffect->Reverb.EchoTime; + break; + + case AL_EAXREVERB_ECHO_DEPTH: + *pflValue = ALEffect->Reverb.EchoDepth; + break; + + case AL_EAXREVERB_MODULATION_TIME: + *pflValue = ALEffect->Reverb.ModulationTime; + break; + + case AL_EAXREVERB_MODULATION_DEPTH: + *pflValue = ALEffect->Reverb.ModulationDepth; + break; + + case AL_EAXREVERB_HFREFERENCE: + *pflValue = ALEffect->Reverb.HFReference; + break; + + case AL_EAXREVERB_LFREFERENCE: + *pflValue = ALEffect->Reverb.LFReference; + break; + + case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: + *pflValue = ALEffect->Reverb.RoomRolloffFactor; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_REVERB) + { + switch(param) + { + case AL_REVERB_DENSITY: + *pflValue = ALEffect->Reverb.Density; + break; + + case AL_REVERB_DIFFUSION: + *pflValue = ALEffect->Reverb.Diffusion; + break; + + case AL_REVERB_GAIN: + *pflValue = ALEffect->Reverb.Gain; + break; + + case AL_REVERB_GAINHF: + *pflValue = ALEffect->Reverb.GainHF; + break; + + case AL_REVERB_DECAY_TIME: + *pflValue = ALEffect->Reverb.DecayTime; + break; + + case AL_REVERB_DECAY_HFRATIO: + *pflValue = ALEffect->Reverb.DecayHFRatio; + break; + + case AL_REVERB_REFLECTIONS_GAIN: + *pflValue = ALEffect->Reverb.ReflectionsGain; + break; + + case AL_REVERB_REFLECTIONS_DELAY: + *pflValue = ALEffect->Reverb.ReflectionsDelay; + break; + + case AL_REVERB_LATE_REVERB_GAIN: + *pflValue = ALEffect->Reverb.LateReverbGain; + break; + + case AL_REVERB_LATE_REVERB_DELAY: + *pflValue = ALEffect->Reverb.LateReverbDelay; + break; + + case AL_REVERB_AIR_ABSORPTION_GAINHF: + *pflValue = ALEffect->Reverb.AirAbsorptionGainHF; + break; + + case AL_REVERB_ROOM_ROLLOFF_FACTOR: + *pflValue = ALEffect->Reverb.RoomRolloffFactor; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_ECHO) + { + switch(param) + { + case AL_ECHO_DELAY: + *pflValue = ALEffect->Echo.Delay; + break; + + case AL_ECHO_LRDELAY: + *pflValue = ALEffect->Echo.LRDelay; + break; + + case AL_ECHO_DAMPING: + *pflValue = ALEffect->Echo.Damping; + break; + + case AL_ECHO_FEEDBACK: + *pflValue = ALEffect->Echo.Feedback; + break; + + case AL_ECHO_SPREAD: + *pflValue = ALEffect->Echo.Spread; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_RING_MODULATOR) + { + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + *pflValue = ALEffect->Modulator.Frequency; + break; + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + *pflValue = ALEffect->Modulator.HighPassCutoff; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_ENUM); + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL) + { + if(ALEffect->type == AL_EFFECT_EAXREVERB) + { + switch(param) + { + case AL_EAXREVERB_DENSITY: + case AL_EAXREVERB_DIFFUSION: + case AL_EAXREVERB_GAIN: + case AL_EAXREVERB_GAINHF: + case AL_EAXREVERB_GAINLF: + case AL_EAXREVERB_DECAY_TIME: + case AL_EAXREVERB_DECAY_HFRATIO: + case AL_EAXREVERB_DECAY_LFRATIO: + case AL_EAXREVERB_REFLECTIONS_GAIN: + case AL_EAXREVERB_REFLECTIONS_DELAY: + case AL_EAXREVERB_LATE_REVERB_GAIN: + case AL_EAXREVERB_LATE_REVERB_DELAY: + case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: + case AL_EAXREVERB_ECHO_TIME: + case AL_EAXREVERB_ECHO_DEPTH: + case AL_EAXREVERB_MODULATION_TIME: + case AL_EAXREVERB_MODULATION_DEPTH: + case AL_EAXREVERB_HFREFERENCE: + case AL_EAXREVERB_LFREFERENCE: + case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: + alGetEffectf(effect, param, pflValues); + break; + + case AL_EAXREVERB_REFLECTIONS_PAN: + pflValues[0] = ALEffect->Reverb.ReflectionsPan[0]; + pflValues[1] = ALEffect->Reverb.ReflectionsPan[1]; + pflValues[2] = ALEffect->Reverb.ReflectionsPan[2]; + break; + case AL_EAXREVERB_LATE_REVERB_PAN: + pflValues[0] = ALEffect->Reverb.LateReverbPan[0]; + pflValues[1] = ALEffect->Reverb.LateReverbPan[1]; + pflValues[2] = ALEffect->Reverb.LateReverbPan[2]; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_REVERB) + { + switch(param) + { + case AL_REVERB_DENSITY: + case AL_REVERB_DIFFUSION: + case AL_REVERB_GAIN: + case AL_REVERB_GAINHF: + case AL_REVERB_DECAY_TIME: + case AL_REVERB_DECAY_HFRATIO: + case AL_REVERB_REFLECTIONS_GAIN: + case AL_REVERB_REFLECTIONS_DELAY: + case AL_REVERB_LATE_REVERB_GAIN: + case AL_REVERB_LATE_REVERB_DELAY: + case AL_REVERB_AIR_ABSORPTION_GAINHF: + case AL_REVERB_ROOM_ROLLOFF_FACTOR: + alGetEffectf(effect, param, pflValues); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_ECHO) + { + switch(param) + { + case AL_ECHO_DELAY: + case AL_ECHO_LRDELAY: + case AL_ECHO_DAMPING: + case AL_ECHO_FEEDBACK: + case AL_ECHO_SPREAD: + alGetEffectf(effect, param, pflValues); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else if(ALEffect->type == AL_EFFECT_RING_MODULATOR) + { + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + alGetEffectf(effect, param, pflValues); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_ENUM); + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + + +ALvoid ReleaseALEffects(ALCdevice *device) +{ + ALsizei i; + for(i = 0;i < device->EffectMap.size;i++) + { + ALeffect *temp = device->EffectMap.array[i].value; + device->EffectMap.array[i].value = NULL; + + // Release effect structure + ALTHUNK_REMOVEENTRY(temp->effect); + memset(temp, 0, sizeof(ALeffect)); + free(temp); + } +} + + +static void InitEffectParams(ALeffect *effect, ALenum type) +{ + effect->type = type; + switch(type) + { + /* NOTE: Standard reverb and EAX reverb use the same defaults for the + * shared parameters, and EAX's additional parameters default to + * values assumed by standard reverb. + */ + case AL_EFFECT_EAXREVERB: + case AL_EFFECT_REVERB: + effect->Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY; + effect->Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; + effect->Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN; + effect->Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF; + effect->Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF; + effect->Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; + effect->Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; + effect->Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; + effect->Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN; + effect->Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY; + effect->Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + effect->Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + effect->Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + effect->Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN; + effect->Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY; + effect->Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + effect->Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + effect->Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + effect->Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME; + effect->Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH; + effect->Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME; + effect->Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH; + effect->Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF; + effect->Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; + effect->Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; + effect->Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; + effect->Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT; + break; + case AL_EFFECT_ECHO: + effect->Echo.Delay = AL_ECHO_DEFAULT_DELAY; + effect->Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY; + effect->Echo.Damping = AL_ECHO_DEFAULT_DAMPING; + effect->Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK; + effect->Echo.Spread = AL_ECHO_DEFAULT_SPREAD; + break; + case AL_EFFECT_RING_MODULATOR: + effect->Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY; + effect->Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF; + effect->Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM; + break; + } +} diff --git a/project/jni/openal/src/OpenAL32/alError.c b/project/jni/openal/src/OpenAL32/alError.c new file mode 100644 index 000000000..43b8e44df --- /dev/null +++ b/project/jni/openal/src/OpenAL32/alError.c @@ -0,0 +1,47 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "alMain.h" +#include "AL/alc.h" +#include "alError.h" + +AL_API ALenum AL_APIENTRY alGetError(ALvoid) +{ + ALCcontext *Context; + ALenum errorCode; + + Context = GetContextSuspended(); + if(!Context) return AL_INVALID_OPERATION; + + errorCode = Context->LastError; + Context->LastError = AL_NO_ERROR; + + ProcessContext(Context); + + return errorCode; +} + +ALvoid alSetError(ALCcontext *Context, ALenum errorCode) +{ + if(Context->LastError == AL_NO_ERROR) + Context->LastError = errorCode; +} diff --git a/project/jni/openal/src/OpenAL32/alExtension.c b/project/jni/openal/src/OpenAL32/alExtension.c new file mode 100644 index 000000000..15b8c0e27 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/alExtension.c @@ -0,0 +1,329 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "alError.h" +#include "alMain.h" +#include "alFilter.h" +#include "alEffect.h" +#include "alAuxEffectSlot.h" +#include "alDatabuffer.h" +#include "alSource.h" +#include "alBuffer.h" +#include "AL/al.h" +#include "AL/alc.h" + +typedef struct ALenums { + const ALchar *enumName; + ALenum value; +} ALenums; + + +static const ALenums enumeration[] = { + // Types + { "AL_INVALID", AL_INVALID }, + { "AL_NONE", AL_NONE }, + { "AL_FALSE", AL_FALSE }, + { "AL_TRUE", AL_TRUE }, + + // Source and Listener Properties + { "AL_SOURCE_RELATIVE", AL_SOURCE_RELATIVE }, + { "AL_CONE_INNER_ANGLE", AL_CONE_INNER_ANGLE }, + { "AL_CONE_OUTER_ANGLE", AL_CONE_OUTER_ANGLE }, + { "AL_PITCH", AL_PITCH }, + { "AL_POSITION", AL_POSITION }, + { "AL_DIRECTION", AL_DIRECTION }, + { "AL_VELOCITY", AL_VELOCITY }, + { "AL_LOOPING", AL_LOOPING }, + { "AL_BUFFER", AL_BUFFER }, + { "AL_GAIN", AL_GAIN }, + { "AL_MIN_GAIN", AL_MIN_GAIN }, + { "AL_MAX_GAIN", AL_MAX_GAIN }, + { "AL_ORIENTATION", AL_ORIENTATION }, + { "AL_REFERENCE_DISTANCE", AL_REFERENCE_DISTANCE }, + { "AL_ROLLOFF_FACTOR", AL_ROLLOFF_FACTOR }, + { "AL_CONE_OUTER_GAIN", AL_CONE_OUTER_GAIN }, + { "AL_MAX_DISTANCE", AL_MAX_DISTANCE }, + { "AL_SEC_OFFSET", AL_SEC_OFFSET }, + { "AL_SAMPLE_OFFSET", AL_SAMPLE_OFFSET }, + { "AL_BYTE_OFFSET", AL_BYTE_OFFSET }, + { "AL_SOURCE_TYPE", AL_SOURCE_TYPE }, + { "AL_STATIC", AL_STATIC }, + { "AL_STREAMING", AL_STREAMING }, + { "AL_UNDETERMINED", AL_UNDETERMINED }, + { "AL_METERS_PER_UNIT", AL_METERS_PER_UNIT }, + + // Source EFX Properties + { "AL_DIRECT_FILTER", AL_DIRECT_FILTER }, + { "AL_AUXILIARY_SEND_FILTER", AL_AUXILIARY_SEND_FILTER }, + { "AL_AIR_ABSORPTION_FACTOR", AL_AIR_ABSORPTION_FACTOR }, + { "AL_ROOM_ROLLOFF_FACTOR", AL_ROOM_ROLLOFF_FACTOR }, + { "AL_CONE_OUTER_GAINHF", AL_CONE_OUTER_GAINHF }, + { "AL_DIRECT_FILTER_GAINHF_AUTO", AL_DIRECT_FILTER_GAINHF_AUTO }, + { "AL_AUXILIARY_SEND_FILTER_GAIN_AUTO", AL_AUXILIARY_SEND_FILTER_GAIN_AUTO }, + { "AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO", AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO}, + + // Source State information + { "AL_SOURCE_STATE", AL_SOURCE_STATE }, + { "AL_INITIAL", AL_INITIAL }, + { "AL_PLAYING", AL_PLAYING }, + { "AL_PAUSED", AL_PAUSED }, + { "AL_STOPPED", AL_STOPPED }, + + // Queue information + { "AL_BUFFERS_QUEUED", AL_BUFFERS_QUEUED }, + { "AL_BUFFERS_PROCESSED", AL_BUFFERS_PROCESSED }, + + // Buffer Formats + { "AL_FORMAT_MONO8", AL_FORMAT_MONO8 }, + { "AL_FORMAT_MONO16", AL_FORMAT_MONO16 }, + { "AL_FORMAT_MONO_FLOAT32", AL_FORMAT_MONO_FLOAT32 }, + { "AL_FORMAT_MONO_DOUBLE_EXT", AL_FORMAT_MONO_DOUBLE_EXT }, + { "AL_FORMAT_STEREO8", AL_FORMAT_STEREO8 }, + { "AL_FORMAT_STEREO16", AL_FORMAT_STEREO16 }, + { "AL_FORMAT_STEREO_FLOAT32", AL_FORMAT_STEREO_FLOAT32 }, + { "AL_FORMAT_STEREO_DOUBLE_EXT", AL_FORMAT_STEREO_DOUBLE_EXT }, + { "AL_FORMAT_MONO_IMA4", AL_FORMAT_MONO_IMA4 }, + { "AL_FORMAT_STEREO_IMA4", AL_FORMAT_STEREO_IMA4 }, + { "AL_FORMAT_QUAD8_LOKI", AL_FORMAT_QUAD8_LOKI }, + { "AL_FORMAT_QUAD16_LOKI", AL_FORMAT_QUAD16_LOKI }, + { "AL_FORMAT_QUAD8", AL_FORMAT_QUAD8 }, + { "AL_FORMAT_QUAD16", AL_FORMAT_QUAD16 }, + { "AL_FORMAT_QUAD32", AL_FORMAT_QUAD32 }, + { "AL_FORMAT_51CHN8", AL_FORMAT_51CHN8 }, + { "AL_FORMAT_51CHN16", AL_FORMAT_51CHN16 }, + { "AL_FORMAT_51CHN32", AL_FORMAT_51CHN32 }, + { "AL_FORMAT_61CHN8", AL_FORMAT_61CHN8 }, + { "AL_FORMAT_61CHN16", AL_FORMAT_61CHN16 }, + { "AL_FORMAT_61CHN32", AL_FORMAT_61CHN32 }, + { "AL_FORMAT_71CHN8", AL_FORMAT_71CHN8 }, + { "AL_FORMAT_71CHN16", AL_FORMAT_71CHN16 }, + { "AL_FORMAT_71CHN32", AL_FORMAT_71CHN32 }, + { "AL_FORMAT_REAR8", AL_FORMAT_REAR8 }, + { "AL_FORMAT_REAR16", AL_FORMAT_REAR16 }, + { "AL_FORMAT_REAR32", AL_FORMAT_REAR32 }, + { "AL_FORMAT_MONO_MULAW", AL_FORMAT_MONO_MULAW }, + { "AL_FORMAT_MONO_MULAW_EXT", AL_FORMAT_MONO_MULAW }, + { "AL_FORMAT_STEREO_MULAW", AL_FORMAT_STEREO_MULAW }, + { "AL_FORMAT_STEREO_MULAW_EXT", AL_FORMAT_STEREO_MULAW }, + { "AL_FORMAT_QUAD_MULAW", AL_FORMAT_QUAD_MULAW }, + { "AL_FORMAT_51CHN_MULAW", AL_FORMAT_51CHN_MULAW }, + { "AL_FORMAT_61CHN_MULAW", AL_FORMAT_61CHN_MULAW }, + { "AL_FORMAT_71CHN_MULAW", AL_FORMAT_71CHN_MULAW }, + { "AL_FORMAT_REAR_MULAW", AL_FORMAT_REAR_MULAW }, + + // Buffer attributes + { "AL_FREQUENCY", AL_FREQUENCY }, + { "AL_BITS", AL_BITS }, + { "AL_CHANNELS", AL_CHANNELS }, + { "AL_SIZE", AL_SIZE }, + + // Buffer States (not supported yet) + { "AL_UNUSED", AL_UNUSED }, + { "AL_PENDING", AL_PENDING }, + { "AL_PROCESSED", AL_PROCESSED }, + + // AL Error Messages + { "AL_NO_ERROR", AL_NO_ERROR }, + { "AL_INVALID_NAME", AL_INVALID_NAME }, + { "AL_INVALID_ENUM", AL_INVALID_ENUM }, + { "AL_INVALID_VALUE", AL_INVALID_VALUE }, + { "AL_INVALID_OPERATION", AL_INVALID_OPERATION }, + { "AL_OUT_OF_MEMORY", AL_OUT_OF_MEMORY }, + + // Context strings + { "AL_VENDOR", AL_VENDOR }, + { "AL_VERSION", AL_VERSION }, + { "AL_RENDERER", AL_RENDERER }, + { "AL_EXTENSIONS", AL_EXTENSIONS }, + + // Global states + { "AL_DOPPLER_FACTOR", AL_DOPPLER_FACTOR }, + { "AL_DOPPLER_VELOCITY", AL_DOPPLER_VELOCITY }, + { "AL_DISTANCE_MODEL", AL_DISTANCE_MODEL }, + { "AL_SPEED_OF_SOUND", AL_SPEED_OF_SOUND }, + { "AL_SOURCE_DISTANCE_MODEL", AL_SOURCE_DISTANCE_MODEL }, + + // Distance Models + { "AL_INVERSE_DISTANCE", AL_INVERSE_DISTANCE }, + { "AL_INVERSE_DISTANCE_CLAMPED", AL_INVERSE_DISTANCE_CLAMPED }, + { "AL_LINEAR_DISTANCE", AL_LINEAR_DISTANCE }, + { "AL_LINEAR_DISTANCE_CLAMPED", AL_LINEAR_DISTANCE_CLAMPED }, + { "AL_EXPONENT_DISTANCE", AL_EXPONENT_DISTANCE }, + { "AL_EXPONENT_DISTANCE_CLAMPED", AL_EXPONENT_DISTANCE_CLAMPED }, + + // Filter types + { "AL_FILTER_TYPE", AL_FILTER_TYPE }, + { "AL_FILTER_NULL", AL_FILTER_NULL }, + { "AL_FILTER_LOWPASS", AL_FILTER_LOWPASS }, +#if 0 + { "AL_FILTER_HIGHPASS", AL_FILTER_HIGHPASS }, + { "AL_FILTER_BANDPASS", AL_FILTER_BANDPASS }, +#endif + + // Filter params + { "AL_LOWPASS_GAIN", AL_LOWPASS_GAIN }, + { "AL_LOWPASS_GAINHF", AL_LOWPASS_GAINHF }, + + // Effect types + { "AL_EFFECT_TYPE", AL_EFFECT_TYPE }, + { "AL_EFFECT_NULL", AL_EFFECT_NULL }, + { "AL_EFFECT_REVERB", AL_EFFECT_REVERB }, + { "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB }, +#if 0 + { "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS }, + { "AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION }, +#endif + { "AL_EFFECT_ECHO", AL_EFFECT_ECHO }, +#if 0 + { "AL_EFFECT_FLANGER", AL_EFFECT_FLANGER }, + { "AL_EFFECT_FREQUENCY_SHIFTER", AL_EFFECT_FREQUENCY_SHIFTER }, + { "AL_EFFECT_VOCAL_MORPHER", AL_EFFECT_VOCAL_MORPHER }, + { "AL_EFFECT_PITCH_SHIFTER", AL_EFFECT_PITCH_SHIFTER }, +#endif + { "AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR }, +#if 0 + { "AL_EFFECT_AUTOWAH", AL_EFFECT_AUTOWAH }, + { "AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR }, + { "AL_EFFECT_EQUALIZER", AL_EFFECT_EQUALIZER }, +#endif + + // Reverb params + { "AL_REVERB_DENSITY", AL_REVERB_DENSITY }, + { "AL_REVERB_DIFFUSION", AL_REVERB_DIFFUSION }, + { "AL_REVERB_GAIN", AL_REVERB_GAIN }, + { "AL_REVERB_GAINHF", AL_REVERB_GAINHF }, + { "AL_REVERB_DECAY_TIME", AL_REVERB_DECAY_TIME }, + { "AL_REVERB_DECAY_HFRATIO", AL_REVERB_DECAY_HFRATIO }, + { "AL_REVERB_REFLECTIONS_GAIN", AL_REVERB_REFLECTIONS_GAIN }, + { "AL_REVERB_REFLECTIONS_DELAY", AL_REVERB_REFLECTIONS_DELAY }, + { "AL_REVERB_LATE_REVERB_GAIN", AL_REVERB_LATE_REVERB_GAIN }, + { "AL_REVERB_LATE_REVERB_DELAY", AL_REVERB_LATE_REVERB_DELAY }, + { "AL_REVERB_AIR_ABSORPTION_GAINHF", AL_REVERB_AIR_ABSORPTION_GAINHF }, + { "AL_REVERB_ROOM_ROLLOFF_FACTOR", AL_REVERB_ROOM_ROLLOFF_FACTOR }, + { "AL_REVERB_DECAY_HFLIMIT", AL_REVERB_DECAY_HFLIMIT }, + + // EAX Reverb params + { "AL_EAXREVERB_DENSITY", AL_EAXREVERB_DENSITY }, + { "AL_EAXREVERB_DIFFUSION", AL_EAXREVERB_DIFFUSION }, + { "AL_EAXREVERB_GAIN", AL_EAXREVERB_GAIN }, + { "AL_EAXREVERB_GAINHF", AL_EAXREVERB_GAINHF }, + { "AL_EAXREVERB_GAINLF", AL_EAXREVERB_GAINLF }, + { "AL_EAXREVERB_DECAY_TIME", AL_EAXREVERB_DECAY_TIME }, + { "AL_EAXREVERB_DECAY_HFRATIO", AL_EAXREVERB_DECAY_HFRATIO }, + { "AL_EAXREVERB_DECAY_LFRATIO", AL_EAXREVERB_DECAY_LFRATIO }, + { "AL_EAXREVERB_REFLECTIONS_GAIN", AL_EAXREVERB_REFLECTIONS_GAIN }, + { "AL_EAXREVERB_REFLECTIONS_DELAY", AL_EAXREVERB_REFLECTIONS_DELAY }, + { "AL_EAXREVERB_REFLECTIONS_PAN", AL_EAXREVERB_REFLECTIONS_PAN }, + { "AL_EAXREVERB_LATE_REVERB_GAIN", AL_EAXREVERB_LATE_REVERB_GAIN }, + { "AL_EAXREVERB_LATE_REVERB_DELAY", AL_EAXREVERB_LATE_REVERB_DELAY }, + { "AL_EAXREVERB_LATE_REVERB_PAN", AL_EAXREVERB_LATE_REVERB_PAN }, + { "AL_EAXREVERB_ECHO_TIME", AL_EAXREVERB_ECHO_TIME }, + { "AL_EAXREVERB_ECHO_DEPTH", AL_EAXREVERB_ECHO_DEPTH }, + { "AL_EAXREVERB_MODULATION_TIME", AL_EAXREVERB_MODULATION_TIME }, + { "AL_EAXREVERB_MODULATION_DEPTH", AL_EAXREVERB_MODULATION_DEPTH }, + { "AL_EAXREVERB_AIR_ABSORPTION_GAINHF", AL_EAXREVERB_AIR_ABSORPTION_GAINHF }, + { "AL_EAXREVERB_HFREFERENCE", AL_EAXREVERB_HFREFERENCE }, + { "AL_EAXREVERB_LFREFERENCE", AL_EAXREVERB_LFREFERENCE }, + { "AL_EAXREVERB_ROOM_ROLLOFF_FACTOR", AL_EAXREVERB_ROOM_ROLLOFF_FACTOR }, + { "AL_EAXREVERB_DECAY_HFLIMIT", AL_EAXREVERB_DECAY_HFLIMIT }, + + // Echo params + { "AL_ECHO_DELAY", AL_ECHO_DELAY }, + { "AL_ECHO_LRDELAY", AL_ECHO_LRDELAY }, + { "AL_ECHO_DAMPING", AL_ECHO_DAMPING }, + { "AL_ECHO_FEEDBACK", AL_ECHO_FEEDBACK }, + { "AL_ECHO_SPREAD", AL_ECHO_SPREAD }, + + // Ring Modulator params + { "AL_RING_MODULATOR_FREQUENCY", AL_RING_MODULATOR_FREQUENCY }, + { "AL_RING_MODULATOR_HIGHPASS_CUTOFF", AL_RING_MODULATOR_HIGHPASS_CUTOFF }, + { "AL_RING_MODULATOR_WAVEFORM", AL_RING_MODULATOR_WAVEFORM }, + + + // Default + { NULL, (ALenum)0 } +}; + + + +AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) +{ + ALboolean bIsSupported = AL_FALSE; + ALCcontext *pContext; + const char *ptr; + size_t len; + + pContext = GetContextSuspended(); + if(!pContext) return AL_FALSE; + + if(!extName) + { + alSetError(pContext, AL_INVALID_VALUE); + ProcessContext(pContext); + return AL_FALSE; + } + + len = strlen(extName); + ptr = pContext->ExtensionList; + while(ptr && *ptr) + { + if(strncasecmp(ptr, extName, len) == 0 && + (ptr[len] == '\0' || isspace(ptr[len]))) + { + bIsSupported = AL_TRUE; + break; + } + if((ptr=strchr(ptr, ' ')) != NULL) + { + do { + ++ptr; + } while(isspace(*ptr)); + } + } + + ProcessContext(pContext); + + return bIsSupported; +} + + +AL_API ALvoid* AL_APIENTRY alGetProcAddress(const ALchar *funcName) +{ + if(!funcName) + return NULL; + return alcGetProcAddress(NULL, funcName); +} + +AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName) +{ + ALsizei i = 0; + + while(enumeration[i].enumName && + strcmp(enumeration[i].enumName, enumName) != 0) + i++; + + return enumeration[i].value; +} diff --git a/project/jni/openal/src/OpenAL32/alFilter.c b/project/jni/openal/src/OpenAL32/alFilter.c new file mode 100644 index 000000000..35a58c7a1 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/alFilter.c @@ -0,0 +1,431 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alFilter.h" +#include "alThunk.h" +#include "alError.h" + + +static void InitFilterParams(ALfilter *filter, ALenum type); + +#define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k))) + +AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) +{ + ALCcontext *Context; + ALsizei i=0; + + Context = GetContextSuspended(); + if(!Context) return; + + if (n > 0) + { + ALCdevice *device = Context->Device; + + // Check that enough memory has been allocted in the 'filters' array for n Filters + if (!IsBadWritePtr((void*)filters, n * sizeof(ALuint))) + { + ALenum err; + + while(i < n) + { + ALfilter *filter = calloc(1, sizeof(ALfilter)); + if(!filter) + { + alSetError(Context, AL_OUT_OF_MEMORY); + alDeleteFilters(i, filters); + break; + } + + filter->filter = ALTHUNK_ADDENTRY(filter); + err = InsertUIntMapEntry(&device->FilterMap, filter->filter, + filter); + if(err != AL_NO_ERROR) + { + ALTHUNK_REMOVEENTRY(filter->filter); + memset(filter, 0, sizeof(ALfilter)); + free(filter); + + alSetError(Context, err); + alDeleteFilters(i, filters); + break; + } + + filters[i++] = filter->filter; + InitFilterParams(filter, AL_FILTER_NULL); + } + } + } + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters) +{ + ALCcontext *Context; + ALfilter *ALFilter; + ALsizei i; + + Context = GetContextSuspended(); + if(!Context) return; + + if (n >= 0) + { + ALCdevice *device = Context->Device; + + // Check that all filters are valid + for (i = 0; i < n; i++) + { + if(!filters[i]) + continue; + + if(!LookupFilter(device->FilterMap, filters[i])) + { + alSetError(Context, AL_INVALID_NAME); + break; + } + } + + if (i == n) + { + // All filters are valid + for (i = 0; i < n; i++) + { + // Recheck that the filter is valid, because there could be duplicated names + if((ALFilter=LookupFilter(device->FilterMap, filters[i])) != NULL) + { + RemoveUIntMapKey(&device->FilterMap, ALFilter->filter); + ALTHUNK_REMOVEENTRY(ALFilter->filter); + + memset(ALFilter, 0, sizeof(ALfilter)); + free(ALFilter); + } + } + } + } + else + alSetError(Context, AL_INVALID_VALUE); + + ProcessContext(Context); +} + +AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) +{ + ALCcontext *Context; + ALboolean result; + + Context = GetContextSuspended(); + if(!Context) return AL_FALSE; + + result = ((!filter || LookupFilter(Context->Device->FilterMap, filter)) ? + AL_TRUE : AL_FALSE); + + ProcessContext(Context); + + return result; +} + +AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL) + { + switch(param) + { + case AL_FILTER_TYPE: + if(iValue == AL_FILTER_NULL || + iValue == AL_FILTER_LOWPASS) + InitFilterParams(ALFilter, iValue); + else + alSetError(Context, AL_INVALID_VALUE); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues) +{ + ALCcontext *Context; + ALCdevice *Device; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if(LookupFilter(Device->FilterMap, filter) != NULL) + { + switch(param) + { + case AL_FILTER_TYPE: + alFilteri(filter, param, piValues[0]); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL) + { + switch(ALFilter->type) + { + case AL_FILTER_LOWPASS: + switch(param) + { + case AL_LOWPASS_GAIN: + if(flValue >= 0.0f && flValue <= 1.0f) + ALFilter->Gain = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + case AL_LOWPASS_GAINHF: + if(flValue >= 0.0f && flValue <= 1.0f) + ALFilter->GainHF = flValue; + else + alSetError(Context, AL_INVALID_VALUE); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues) +{ + ALCcontext *Context; + ALCdevice *Device; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if(LookupFilter(Device->FilterMap, filter) != NULL) + { + switch(param) + { + default: + alFilterf(filter, param, pflValues[0]); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL) + { + switch(param) + { + case AL_FILTER_TYPE: + *piValue = ALFilter->type; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues) +{ + ALCcontext *Context; + ALCdevice *Device; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if(LookupFilter(Device->FilterMap, filter) != NULL) + { + switch(param) + { + case AL_FILTER_TYPE: + alGetFilteri(filter, param, piValues); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL) + { + switch(ALFilter->type) + { + case AL_FILTER_LOWPASS: + switch(param) + { + case AL_LOWPASS_GAIN: + *pflValue = ALFilter->Gain; + break; + + case AL_LOWPASS_GAINHF: + *pflValue = ALFilter->GainHF; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues) +{ + ALCcontext *Context; + ALCdevice *Device; + + Context = GetContextSuspended(); + if(!Context) return; + + Device = Context->Device; + if(LookupFilter(Device->FilterMap, filter) != NULL) + { + switch(param) + { + default: + alGetFilterf(filter, param, pflValues); + break; + } + } + else + alSetError(Context, AL_INVALID_NAME); + + ProcessContext(Context); +} + + +ALvoid ReleaseALFilters(ALCdevice *device) +{ + ALsizei i; + for(i = 0;i < device->FilterMap.size;i++) + { + ALfilter *temp = device->FilterMap.array[i].value; + device->FilterMap.array[i].value = NULL; + + // Release filter structure + ALTHUNK_REMOVEENTRY(temp->filter); + memset(temp, 0, sizeof(ALfilter)); + free(temp); + } +} + + +static void InitFilterParams(ALfilter *filter, ALenum type) +{ + filter->type = type; + + filter->Gain = 1.0; + filter->GainHF = 1.0; +} diff --git a/project/jni/openal/src/OpenAL32/alListener.c b/project/jni/openal/src/OpenAL32/alListener.c new file mode 100644 index 000000000..b3c192dc6 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/alListener.c @@ -0,0 +1,484 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "alMain.h" +#include "AL/alc.h" +#include "alError.h" +#include "alListener.h" +#include "alSource.h" + +AL_API ALvoid AL_APIENTRY alListenerf(ALenum eParam, ALfloat flValue) +{ + ALCcontext *pContext; + ALboolean updateAll = AL_FALSE; + + pContext = GetContextSuspended(); + if(!pContext) return; + + switch(eParam) + { + case AL_GAIN: + if(flValue >= 0.0f) + { + pContext->Listener.Gain = flValue; + updateAll = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_METERS_PER_UNIT: + if(flValue > 0.0f) + { + pContext->Listener.MetersPerUnit = flValue; + updateAll = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + + // Force updating the sources for these parameters, since even head- + // relative sources are affected + if(updateAll) + { + ALsizei pos; + for(pos = 0;pos < pContext->SourceMap.size;pos++) + { + ALsource *source = pContext->SourceMap.array[pos].value; + source->NeedsUpdate = AL_TRUE; + } + } + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alListener3f(ALenum eParam, ALfloat flValue1, ALfloat flValue2, ALfloat flValue3) +{ + ALCcontext *pContext; + ALboolean updateWorld = AL_FALSE; + + pContext = GetContextSuspended(); + if(!pContext) return; + + switch(eParam) + { + case AL_POSITION: + pContext->Listener.Position[0] = flValue1; + pContext->Listener.Position[1] = flValue2; + pContext->Listener.Position[2] = flValue3; + updateWorld = AL_TRUE; + break; + + case AL_VELOCITY: + pContext->Listener.Velocity[0] = flValue1; + pContext->Listener.Velocity[1] = flValue2; + pContext->Listener.Velocity[2] = flValue3; + updateWorld = AL_TRUE; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + + if(updateWorld) + { + ALsizei pos; + for(pos = 0;pos < pContext->SourceMap.size;pos++) + { + ALsource *source = pContext->SourceMap.array[pos].value; + if(!source->bHeadRelative) + source->NeedsUpdate = AL_TRUE; + } + } + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alListenerfv(ALenum eParam, const ALfloat *pflValues) +{ + ALCcontext *pContext; + ALboolean updateWorld = AL_FALSE; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(pflValues) + { + switch(eParam) + { + case AL_GAIN: + case AL_METERS_PER_UNIT: + alListenerf(eParam, pflValues[0]); + break; + + case AL_POSITION: + case AL_VELOCITY: + alListener3f(eParam, pflValues[0], pflValues[1], pflValues[2]); + break; + + case AL_ORIENTATION: + // AT then UP + pContext->Listener.Forward[0] = pflValues[0]; + pContext->Listener.Forward[1] = pflValues[1]; + pContext->Listener.Forward[2] = pflValues[2]; + pContext->Listener.Up[0] = pflValues[3]; + pContext->Listener.Up[1] = pflValues[4]; + pContext->Listener.Up[2] = pflValues[5]; + updateWorld = AL_TRUE; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_VALUE); + + if(updateWorld) + { + ALsizei pos; + for(pos = 0;pos < pContext->SourceMap.size;pos++) + { + ALsource *source = pContext->SourceMap.array[pos].value; + if(!source->bHeadRelative) + source->NeedsUpdate = AL_TRUE; + } + } + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alListeneri(ALenum eParam, ALint lValue) +{ + ALCcontext *pContext; + + (void)lValue; + + pContext = GetContextSuspended(); + if(!pContext) return; + + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alListener3i(ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3) +{ + ALCcontext *pContext; + + pContext = GetContextSuspended(); + if(!pContext) return; + + switch(eParam) + { + case AL_POSITION: + case AL_VELOCITY: + alListener3f(eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3); + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alListeneriv( ALenum eParam, const ALint* plValues ) +{ + ALCcontext *pContext; + ALfloat flValues[6]; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(plValues) + { + switch(eParam) + { + case AL_POSITION: + case AL_VELOCITY: + flValues[0] = (ALfloat)plValues[0]; + flValues[1] = (ALfloat)plValues[1]; + flValues[2] = (ALfloat)plValues[2]; + alListenerfv(eParam, flValues); + break; + + case AL_ORIENTATION: + flValues[0] = (ALfloat)plValues[0]; + flValues[1] = (ALfloat)plValues[1]; + flValues[2] = (ALfloat)plValues[2]; + flValues[3] = (ALfloat)plValues[3]; + flValues[4] = (ALfloat)plValues[4]; + flValues[5] = (ALfloat)plValues[5]; + alListenerfv(eParam, flValues); + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum eParam, ALfloat *pflValue) +{ + ALCcontext *pContext; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(pflValue) + { + switch(eParam) + { + case AL_GAIN: + *pflValue = pContext->Listener.Gain; + break; + + case AL_METERS_PER_UNIT: + *pflValue = pContext->Listener.MetersPerUnit; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum eParam, ALfloat *pflValue1, ALfloat *pflValue2, ALfloat *pflValue3) +{ + ALCcontext *pContext; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(pflValue1 && pflValue2 && pflValue3) + { + switch(eParam) + { + case AL_POSITION: + *pflValue1 = pContext->Listener.Position[0]; + *pflValue2 = pContext->Listener.Position[1]; + *pflValue3 = pContext->Listener.Position[2]; + break; + + case AL_VELOCITY: + *pflValue1 = pContext->Listener.Velocity[0]; + *pflValue2 = pContext->Listener.Velocity[1]; + *pflValue3 = pContext->Listener.Velocity[2]; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum eParam, ALfloat *pflValues) +{ + ALCcontext *pContext; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(pflValues) + { + switch(eParam) + { + case AL_GAIN: + pflValues[0] = pContext->Listener.Gain; + break; + + case AL_METERS_PER_UNIT: + pflValues[0] = pContext->Listener.MetersPerUnit; + break; + + case AL_POSITION: + pflValues[0] = pContext->Listener.Position[0]; + pflValues[1] = pContext->Listener.Position[1]; + pflValues[2] = pContext->Listener.Position[2]; + break; + + case AL_VELOCITY: + pflValues[0] = pContext->Listener.Velocity[0]; + pflValues[1] = pContext->Listener.Velocity[1]; + pflValues[2] = pContext->Listener.Velocity[2]; + break; + + case AL_ORIENTATION: + // AT then UP + pflValues[0] = pContext->Listener.Forward[0]; + pflValues[1] = pContext->Listener.Forward[1]; + pflValues[2] = pContext->Listener.Forward[2]; + pflValues[3] = pContext->Listener.Up[0]; + pflValues[4] = pContext->Listener.Up[1]; + pflValues[5] = pContext->Listener.Up[2]; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum eParam, ALint *plValue) +{ + ALCcontext *pContext; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(plValue) + { + switch(eParam) + { + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alGetListener3i(ALenum eParam, ALint *plValue1, ALint *plValue2, ALint *plValue3) +{ + ALCcontext *pContext; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(plValue1 && plValue2 && plValue3) + { + switch (eParam) + { + case AL_POSITION: + *plValue1 = (ALint)pContext->Listener.Position[0]; + *plValue2 = (ALint)pContext->Listener.Position[1]; + *plValue3 = (ALint)pContext->Listener.Position[2]; + break; + + case AL_VELOCITY: + *plValue1 = (ALint)pContext->Listener.Velocity[0]; + *plValue2 = (ALint)pContext->Listener.Velocity[1]; + *plValue3 = (ALint)pContext->Listener.Velocity[2]; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alGetListeneriv(ALenum eParam, ALint* plValues) +{ + ALCcontext *pContext; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(plValues) + { + switch(eParam) + { + case AL_POSITION: + plValues[0] = (ALint)pContext->Listener.Position[0]; + plValues[1] = (ALint)pContext->Listener.Position[1]; + plValues[2] = (ALint)pContext->Listener.Position[2]; + break; + + case AL_VELOCITY: + plValues[0] = (ALint)pContext->Listener.Velocity[0]; + plValues[1] = (ALint)pContext->Listener.Velocity[1]; + plValues[2] = (ALint)pContext->Listener.Velocity[2]; + break; + + case AL_ORIENTATION: + // AT then UP + plValues[0] = (ALint)pContext->Listener.Forward[0]; + plValues[1] = (ALint)pContext->Listener.Forward[1]; + plValues[2] = (ALint)pContext->Listener.Forward[2]; + plValues[3] = (ALint)pContext->Listener.Up[0]; + plValues[4] = (ALint)pContext->Listener.Up[1]; + plValues[5] = (ALint)pContext->Listener.Up[2]; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} diff --git a/project/jni/openal/src/OpenAL32/alSource.c b/project/jni/openal/src/OpenAL32/alSource.c new file mode 100644 index 000000000..5d7cecede --- /dev/null +++ b/project/jni/openal/src/OpenAL32/alSource.c @@ -0,0 +1,2132 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" +#include "alError.h" +#include "alSource.h" +#include "alBuffer.h" +#include "alThunk.h" +#include "alAuxEffectSlot.h" + +static ALvoid InitSourceParams(ALsource *Source); +static ALvoid GetSourceOffset(ALsource *Source, ALenum eName, ALdouble *Offsets, ALdouble updateLen); +static ALboolean ApplyOffset(ALsource *Source); +static ALint GetByteOffset(ALsource *Source); +static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels); + +#define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k))) +#define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k))) +#define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k))) +#define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k))) + +AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources) +{ + ALCcontext *Context; + ALCdevice *Device; + ALsizei i=0; + + Context = GetContextSuspended(); + if(!Context) return; + + if(n > 0) + { + Device = Context->Device; + + // Check that enough memory has been allocted in the 'sources' array for n Sources + if(!IsBadWritePtr((void*)sources, n * sizeof(ALuint))) + { + // Check that the requested number of sources can be generated + if((Context->SourceMap.size + n) <= (ALsizei)Device->MaxNoOfSources) + { + ALenum err; + + // Add additional sources to the list + while(i < n) + { + ALsource *source = calloc(1, sizeof(ALsource)); + if(!source) + { + alSetError(Context, AL_OUT_OF_MEMORY); + alDeleteSources(i, sources); + break; + } + + source->source = (ALuint)ALTHUNK_ADDENTRY(source); + err = InsertUIntMapEntry(&Context->SourceMap, source->source, + source); + if(err != AL_NO_ERROR) + { + ALTHUNK_REMOVEENTRY(source->source); + memset(source, 0, sizeof(ALsource)); + free(source); + + alSetError(Context, err); + alDeleteSources(i, sources); + break; + } + + sources[i++] = source->source; + InitSourceParams(source); + } + } + else + { + // Not enough resources to create the Sources + alSetError(Context, AL_INVALID_VALUE); + } + } + else + { + // Bad pointer + alSetError(Context, AL_INVALID_VALUE); + } + } + + ProcessContext(Context); +} + + +AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) +{ + ALCcontext *Context; + ALCdevice *Device; + ALsource *Source; + ALsizei i, j; + ALbufferlistitem *BufferList; + ALboolean bSourcesValid = AL_TRUE; + + Context = GetContextSuspended(); + if(!Context) return; + + if(n >= 0) + { + Device = Context->Device; + + // Check that all Sources are valid (and can therefore be deleted) + for (i = 0; i < n; i++) + { + if(LookupSource(Context->SourceMap, sources[i]) == NULL) + { + alSetError(Context, AL_INVALID_NAME); + bSourcesValid = AL_FALSE; + break; + } + } + + if(bSourcesValid) + { + // All Sources are valid, and can be deleted + for(i = 0; i < n; i++) + { + // Recheck that the Source is valid, because there could be duplicated Source names + if((Source=LookupSource(Context->SourceMap, sources[i])) != NULL) + { + for(j = 0;j < Context->ActiveSourceCount;j++) + { + if(Context->ActiveSources[j] == Source) + { + ALsizei end = --(Context->ActiveSourceCount); + Context->ActiveSources[j] = Context->ActiveSources[end]; + break; + } + } + + // For each buffer in the source's queue, decrement its reference counter and remove it + while(Source->queue != NULL) + { + BufferList = Source->queue; + // Decrement buffer's reference counter + if(BufferList->buffer != NULL) + BufferList->buffer->refcount--; + // Update queue to point to next element in list + Source->queue = BufferList->next; + // Release memory allocated for buffer list item + free(BufferList); + } + + for(j = 0;j < MAX_SENDS;++j) + { + if(Source->Send[j].Slot) + Source->Send[j].Slot->refcount--; + Source->Send[j].Slot = NULL; + } + + // Remove Source from list of Sources + RemoveUIntMapKey(&Context->SourceMap, Source->source); + ALTHUNK_REMOVEENTRY(Source->source); + + memset(Source,0,sizeof(ALsource)); + free(Source); + } + } + } + } + else + alSetError(Context, AL_INVALID_VALUE); + + ProcessContext(Context); +} + + +AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) +{ + ALCcontext *Context; + ALboolean result; + + Context = GetContextSuspended(); + if(!Context) return AL_FALSE; + + result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE); + + ProcessContext(Context); + + return result; +} + + +AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue) +{ + ALCcontext *pContext; + ALsource *Source; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if((Source=LookupSource(pContext->SourceMap, source)) != NULL) + { + switch(eParam) + { + case AL_PITCH: + if(flValue >= 0.0f) + { + Source->flPitch = flValue; + if(Source->flPitch < 0.001f) + Source->flPitch = 0.001f; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_CONE_INNER_ANGLE: + if(flValue >= 0.0f && flValue <= 360.0f) + { + Source->flInnerAngle = flValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_CONE_OUTER_ANGLE: + if(flValue >= 0.0f && flValue <= 360.0f) + { + Source->flOuterAngle = flValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_GAIN: + if(flValue >= 0.0f) + { + Source->flGain = flValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_MAX_DISTANCE: + if(flValue >= 0.0f) + { + Source->flMaxDistance = flValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_ROLLOFF_FACTOR: + if(flValue >= 0.0f) + { + Source->flRollOffFactor = flValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_REFERENCE_DISTANCE: + if(flValue >= 0.0f) + { + Source->flRefDistance = flValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_MIN_GAIN: + if(flValue >= 0.0f && flValue <= 1.0f) + { + Source->flMinGain = flValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_MAX_GAIN: + if(flValue >= 0.0f && flValue <= 1.0f) + { + Source->flMaxGain = flValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_CONE_OUTER_GAIN: + if(flValue >= 0.0f && flValue <= 1.0f) + { + Source->flOuterGain = flValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_CONE_OUTER_GAINHF: + if(flValue >= 0.0f && flValue <= 1.0f) + { + Source->OuterGainHF = flValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_AIR_ABSORPTION_FACTOR: + if(flValue >= 0.0f && flValue <= 10.0f) + { + Source->AirAbsorptionFactor = flValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_ROOM_ROLLOFF_FACTOR: + if(flValue >= 0.0f && flValue <= 10.0f) + { + Source->RoomRolloffFactor = flValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_DOPPLER_FACTOR: + if(flValue >= 0.0f && flValue <= 1.0f) + { + Source->DopplerFactor = flValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + if(flValue >= 0.0f) + { + Source->lOffsetType = eParam; + + // Store Offset (convert Seconds into Milliseconds) + if(eParam == AL_SEC_OFFSET) + Source->lOffset = (ALint)(flValue * 1000.0f); + else + Source->lOffset = (ALint)flValue; + + if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED)) + { + if(ApplyOffset(Source) == AL_FALSE) + alSetError(pContext, AL_INVALID_VALUE); + } + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + { + // Invalid Source Name + alSetError(pContext, AL_INVALID_NAME); + } + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3) +{ + ALCcontext *pContext; + ALsource *Source; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if((Source=LookupSource(pContext->SourceMap, source)) != NULL) + { + switch(eParam) + { + case AL_POSITION: + Source->vPosition[0] = flValue1; + Source->vPosition[1] = flValue2; + Source->vPosition[2] = flValue3; + Source->NeedsUpdate = AL_TRUE; + break; + + case AL_VELOCITY: + Source->vVelocity[0] = flValue1; + Source->vVelocity[1] = flValue2; + Source->vVelocity[2] = flValue3; + Source->NeedsUpdate = AL_TRUE; + break; + + case AL_DIRECTION: + Source->vOrientation[0] = flValue1; + Source->vOrientation[1] = flValue2; + Source->vOrientation[2] = flValue3; + Source->NeedsUpdate = AL_TRUE; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues) +{ + ALCcontext *pContext; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(pflValues) + { + if(LookupSource(pContext->SourceMap, source) != NULL) + { + switch(eParam) + { + case AL_PITCH: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_REFERENCE_DISTANCE: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_CONE_OUTER_GAIN: + case AL_CONE_OUTER_GAINHF: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + alSourcef(source, eParam, pflValues[0]); + break; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]); + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue) +{ + ALCcontext *pContext; + ALsource *Source; + ALbufferlistitem *BufferListItem; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if((Source=LookupSource(pContext->SourceMap, source)) != NULL) + { + ALCdevice *device = pContext->Device; + + switch(eParam) + { + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + alSourcef(source, eParam, (ALfloat)lValue); + break; + + case AL_SOURCE_RELATIVE: + if(lValue == AL_FALSE || lValue == AL_TRUE) + { + Source->bHeadRelative = (ALboolean)lValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_LOOPING: + if(lValue == AL_FALSE || lValue == AL_TRUE) + Source->bLooping = (ALboolean)lValue; + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_BUFFER: + if(Source->state == AL_STOPPED || Source->state == AL_INITIAL) + { + ALbuffer *buffer = NULL; + + if(lValue == 0 || + (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL) + { + // Remove all elements in the queue + while(Source->queue != NULL) + { + BufferListItem = Source->queue; + Source->queue = BufferListItem->next; + // Decrement reference counter for buffer + if(BufferListItem->buffer) + BufferListItem->buffer->refcount--; + // Release memory for buffer list item + free(BufferListItem); + // Decrement the number of buffers in the queue + Source->BuffersInQueue--; + } + + // Add the buffer to the queue (as long as it is NOT the NULL buffer) + if(lValue != 0) + { + // Source is now in STATIC mode + Source->lSourceType = AL_STATIC; + + // Add the selected buffer to the queue + BufferListItem = malloc(sizeof(ALbufferlistitem)); + BufferListItem->buffer = buffer; + BufferListItem->next = NULL; + + Source->queue = BufferListItem; + Source->BuffersInQueue = 1; + + // Increment reference counter for buffer + buffer->refcount++; + } + else + { + // Source is now in UNDETERMINED mode + Source->lSourceType = AL_UNDETERMINED; + } + Source->BuffersPlayed = 0; + + // Update AL_BUFFER parameter + Source->Buffer = buffer; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + } + else + alSetError(pContext, AL_INVALID_OPERATION); + break; + + case AL_SOURCE_STATE: + // Query only + alSetError(pContext, AL_INVALID_OPERATION); + break; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + if(lValue >= 0) + { + Source->lOffsetType = eParam; + + // Store Offset (convert Seconds into Milliseconds) + if(eParam == AL_SEC_OFFSET) + Source->lOffset = lValue * 1000; + else + Source->lOffset = lValue; + + if(Source->state == AL_PLAYING || Source->state == AL_PAUSED) + { + if(ApplyOffset(Source) == AL_FALSE) + alSetError(pContext, AL_INVALID_VALUE); + } + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_DIRECT_FILTER: { + ALfilter *filter = NULL; + + if(lValue == 0 || + (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL) + { + if(!filter) + { + Source->DirectFilter.type = AL_FILTER_NULL; + Source->DirectFilter.filter = 0; + } + else + memcpy(&Source->DirectFilter, filter, sizeof(*filter)); + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + } break; + + case AL_DIRECT_FILTER_GAINHF_AUTO: + if(lValue == AL_TRUE || lValue == AL_FALSE) + { + Source->DryGainHFAuto = lValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + if(lValue == AL_TRUE || lValue == AL_FALSE) + { + Source->WetGainAuto = lValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + if(lValue == AL_TRUE || lValue == AL_FALSE) + { + Source->WetGainHFAuto = lValue; + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + case AL_DISTANCE_MODEL: + if(lValue == AL_NONE || + lValue == AL_INVERSE_DISTANCE || + lValue == AL_INVERSE_DISTANCE_CLAMPED || + lValue == AL_LINEAR_DISTANCE || + lValue == AL_LINEAR_DISTANCE_CLAMPED || + lValue == AL_EXPONENT_DISTANCE || + lValue == AL_EXPONENT_DISTANCE_CLAMPED) + { + Source->DistanceModel = lValue; + if(pContext->SourceDistanceModel) + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3) +{ + ALCcontext *pContext; + ALsource *Source; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if((Source=LookupSource(pContext->SourceMap, source)) != NULL) + { + ALCdevice *device = pContext->Device; + + switch (eParam) + { + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3); + break; + + case AL_AUXILIARY_SEND_FILTER: { + ALeffectslot *ALEffectSlot = NULL; + ALfilter *ALFilter = NULL; + + if((ALuint)lValue2 < device->NumAuxSends && + (lValue1 == 0 || + (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) && + (lValue3 == 0 || + (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL)) + { + /* Release refcount on the previous slot, and add one for + * the new slot */ + if(Source->Send[lValue2].Slot) + Source->Send[lValue2].Slot->refcount--; + Source->Send[lValue2].Slot = ALEffectSlot; + if(Source->Send[lValue2].Slot) + Source->Send[lValue2].Slot->refcount++; + + if(!ALFilter) + { + /* Disable filter */ + Source->Send[lValue2].WetFilter.type = 0; + Source->Send[lValue2].WetFilter.filter = 0; + } + else + memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter)); + Source->NeedsUpdate = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + } break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues) +{ + ALCcontext *pContext; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(plValues) + { + if(LookupSource(pContext->SourceMap, source) != NULL) + { + switch(eParam) + { + case AL_SOURCE_RELATIVE: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_LOOPING: + case AL_BUFFER: + case AL_SOURCE_STATE: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_REFERENCE_DISTANCE: + case AL_DIRECT_FILTER: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DISTANCE_MODEL: + alSourcei(source, eParam, plValues[0]); + break; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + case AL_AUXILIARY_SEND_FILTER: + alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]); + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue) +{ + ALCcontext *pContext; + ALsource *Source; + ALdouble Offsets[2]; + ALdouble updateLen; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(pflValue) + { + if((Source=LookupSource(pContext->SourceMap, source)) != NULL) + { + switch(eParam) + { + case AL_PITCH: + *pflValue = Source->flPitch; + break; + + case AL_GAIN: + *pflValue = Source->flGain; + break; + + case AL_MIN_GAIN: + *pflValue = Source->flMinGain; + break; + + case AL_MAX_GAIN: + *pflValue = Source->flMaxGain; + break; + + case AL_MAX_DISTANCE: + *pflValue = Source->flMaxDistance; + break; + + case AL_ROLLOFF_FACTOR: + *pflValue = Source->flRollOffFactor; + break; + + case AL_CONE_OUTER_GAIN: + *pflValue = Source->flOuterGain; + break; + + case AL_CONE_OUTER_GAINHF: + *pflValue = Source->OuterGainHF; + break; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + updateLen = (ALdouble)pContext->Device->UpdateSize / + pContext->Device->Frequency; + GetSourceOffset(Source, eParam, Offsets, updateLen); + *pflValue = Offsets[0]; + break; + + case AL_CONE_INNER_ANGLE: + *pflValue = Source->flInnerAngle; + break; + + case AL_CONE_OUTER_ANGLE: + *pflValue = Source->flOuterAngle; + break; + + case AL_REFERENCE_DISTANCE: + *pflValue = Source->flRefDistance; + break; + + case AL_AIR_ABSORPTION_FACTOR: + *pflValue = Source->AirAbsorptionFactor; + break; + + case AL_ROOM_ROLLOFF_FACTOR: + *pflValue = Source->RoomRolloffFactor; + break; + + case AL_DOPPLER_FACTOR: + *pflValue = Source->DopplerFactor; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3) +{ + ALCcontext *pContext; + ALsource *Source; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(pflValue1 && pflValue2 && pflValue3) + { + if((Source=LookupSource(pContext->SourceMap, source)) != NULL) + { + switch(eParam) + { + case AL_POSITION: + *pflValue1 = Source->vPosition[0]; + *pflValue2 = Source->vPosition[1]; + *pflValue3 = Source->vPosition[2]; + break; + + case AL_VELOCITY: + *pflValue1 = Source->vVelocity[0]; + *pflValue2 = Source->vVelocity[1]; + *pflValue3 = Source->vVelocity[2]; + break; + + case AL_DIRECTION: + *pflValue1 = Source->vOrientation[0]; + *pflValue2 = Source->vOrientation[1]; + *pflValue3 = Source->vOrientation[2]; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues) +{ + ALCcontext *pContext; + ALsource *Source; + ALdouble Offsets[2]; + ALdouble updateLen; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(pflValues) + { + if((Source=LookupSource(pContext->SourceMap, source)) != NULL) + { + switch(eParam) + { + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + alGetSourcef(source, eParam, pflValues); + break; + + case AL_SAMPLE_RW_OFFSETS_EXT: + case AL_BYTE_RW_OFFSETS_EXT: + updateLen = (ALdouble)pContext->Device->UpdateSize / + pContext->Device->Frequency; + GetSourceOffset(Source, eParam, Offsets, updateLen); + pflValues[0] = Offsets[0]; + pflValues[1] = Offsets[1]; + break; + + case AL_POSITION: + pflValues[0] = Source->vPosition[0]; + pflValues[1] = Source->vPosition[1]; + pflValues[2] = Source->vPosition[2]; + break; + + case AL_VELOCITY: + pflValues[0] = Source->vVelocity[0]; + pflValues[1] = Source->vVelocity[1]; + pflValues[2] = Source->vVelocity[2]; + break; + + case AL_DIRECTION: + pflValues[0] = Source->vOrientation[0]; + pflValues[1] = Source->vOrientation[1]; + pflValues[2] = Source->vOrientation[2]; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue) +{ + ALCcontext *pContext; + ALsource *Source; + ALdouble Offsets[2]; + ALdouble updateLen; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(plValue) + { + if((Source=LookupSource(pContext->SourceMap, source)) != NULL) + { + switch(eParam) + { + case AL_MAX_DISTANCE: + *plValue = (ALint)Source->flMaxDistance; + break; + + case AL_ROLLOFF_FACTOR: + *plValue = (ALint)Source->flRollOffFactor; + break; + + case AL_REFERENCE_DISTANCE: + *plValue = (ALint)Source->flRefDistance; + break; + + case AL_SOURCE_RELATIVE: + *plValue = Source->bHeadRelative; + break; + + case AL_CONE_INNER_ANGLE: + *plValue = (ALint)Source->flInnerAngle; + break; + + case AL_CONE_OUTER_ANGLE: + *plValue = (ALint)Source->flOuterAngle; + break; + + case AL_LOOPING: + *plValue = Source->bLooping; + break; + + case AL_BUFFER: + *plValue = (Source->Buffer ? Source->Buffer->buffer : 0); + break; + + case AL_SOURCE_STATE: + *plValue = Source->state; + break; + + case AL_BUFFERS_QUEUED: + *plValue = Source->BuffersInQueue; + break; + + case AL_BUFFERS_PROCESSED: + if(Source->bLooping || Source->lSourceType != AL_STREAMING) + { + /* Buffers on a looping source are in a perpetual state + * of PENDING, so don't report any as PROCESSED */ + *plValue = 0; + } + else + *plValue = Source->BuffersPlayed; + break; + + case AL_SOURCE_TYPE: + *plValue = Source->lSourceType; + break; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + updateLen = (ALdouble)pContext->Device->UpdateSize / + pContext->Device->Frequency; + GetSourceOffset(Source, eParam, Offsets, updateLen); + *plValue = (ALint)Offsets[0]; + break; + + case AL_DIRECT_FILTER: + *plValue = Source->DirectFilter.filter; + break; + + case AL_DIRECT_FILTER_GAINHF_AUTO: + *plValue = Source->DryGainHFAuto; + break; + + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + *plValue = Source->WetGainAuto; + break; + + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + *plValue = Source->WetGainHFAuto; + break; + + case AL_DOPPLER_FACTOR: + *plValue = (ALint)Source->DopplerFactor; + break; + + case AL_DISTANCE_MODEL: + *plValue = Source->DistanceModel; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3) +{ + ALCcontext *pContext; + ALsource *Source; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(plValue1 && plValue2 && plValue3) + { + if((Source=LookupSource(pContext->SourceMap, source)) != NULL) + { + switch(eParam) + { + case AL_POSITION: + *plValue1 = (ALint)Source->vPosition[0]; + *plValue2 = (ALint)Source->vPosition[1]; + *plValue3 = (ALint)Source->vPosition[2]; + break; + + case AL_VELOCITY: + *plValue1 = (ALint)Source->vVelocity[0]; + *plValue2 = (ALint)Source->vVelocity[1]; + *plValue3 = (ALint)Source->vVelocity[2]; + break; + + case AL_DIRECTION: + *plValue1 = (ALint)Source->vOrientation[0]; + *plValue2 = (ALint)Source->vOrientation[1]; + *plValue3 = (ALint)Source->vOrientation[2]; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues) +{ + ALCcontext *pContext; + ALsource *Source; + ALdouble Offsets[2]; + ALdouble updateLen; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(plValues) + { + if((Source=LookupSource(pContext->SourceMap, source)) != NULL) + { + switch(eParam) + { + case AL_SOURCE_RELATIVE: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_LOOPING: + case AL_BUFFER: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_REFERENCE_DISTANCE: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DISTANCE_MODEL: + alGetSourcei(source, eParam, plValues); + break; + + case AL_SAMPLE_RW_OFFSETS_EXT: + case AL_BYTE_RW_OFFSETS_EXT: + updateLen = (ALdouble)pContext->Device->UpdateSize / + pContext->Device->Frequency; + GetSourceOffset(Source, eParam, Offsets, updateLen); + plValues[0] = (ALint)Offsets[0]; + plValues[1] = (ALint)Offsets[1]; + break; + + case AL_POSITION: + plValues[0] = (ALint)Source->vPosition[0]; + plValues[1] = (ALint)Source->vPosition[1]; + plValues[2] = (ALint)Source->vPosition[2]; + break; + + case AL_VELOCITY: + plValues[0] = (ALint)Source->vVelocity[0]; + plValues[1] = (ALint)Source->vVelocity[1]; + plValues[2] = (ALint)Source->vVelocity[2]; + break; + + case AL_DIRECTION: + plValues[0] = (ALint)Source->vOrientation[0]; + plValues[1] = (ALint)Source->vOrientation[1]; + plValues[2] = (ALint)Source->vOrientation[2]; + break; + + default: + alSetError(pContext, AL_INVALID_ENUM); + break; + } + } + else + alSetError(pContext, AL_INVALID_NAME); + } + else + alSetError(pContext, AL_INVALID_VALUE); + + ProcessContext(pContext); +} + + +AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source) +{ + alSourcePlayv(1, &source); +} + +AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) +{ + ALCcontext *Context; + ALsource *Source; + ALbufferlistitem *BufferList; + ALsizei i, j; + + Context = GetContextSuspended(); + if(!Context) return; + + if(!sources) + { + alSetError(Context, AL_INVALID_VALUE); + goto done; + } + + // Check that all the Sources are valid + for(i = 0;i < n;i++) + { + if(!LookupSource(Context->SourceMap, sources[i])) + { + alSetError(Context, AL_INVALID_NAME); + goto done; + } + } + + if(Context->ActiveSourceCount+n < n) + { + alSetError(Context, AL_OUT_OF_MEMORY); + goto done; + } + + while(Context->MaxActiveSources < Context->ActiveSourceCount+n) + { + void *temp = NULL; + ALsizei newcount; + + newcount = Context->MaxActiveSources << 1; + if(newcount > 0) + temp = realloc(Context->ActiveSources, + sizeof(*Context->ActiveSources) * newcount); + if(!temp) + { + alSetError(Context, AL_OUT_OF_MEMORY); + goto done; + } + + Context->ActiveSources = temp; + Context->MaxActiveSources = newcount; + } + + for(i = 0;i < n;i++) + { + Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]); + + // Check that there is a queue containing at least one non-null, non zero length AL Buffer + BufferList = Source->queue; + while(BufferList) + { + if(BufferList->buffer != NULL && BufferList->buffer->size) + break; + BufferList = BufferList->next; + } + + if(!BufferList) + { + Source->BuffersPlayed = Source->BuffersInQueue; + continue; + } + + for(j = 0;j < OUTPUTCHANNELS;j++) + Source->DryGains[j] = 0.0f; + for(j = 0;j < MAX_SENDS;j++) + Source->WetGains[j] = 0.0f; + + if(Source->state != AL_PAUSED) + { + Source->state = AL_PLAYING; + Source->position = 0; + Source->position_fraction = 0; + Source->BuffersPlayed = 0; + + Source->Buffer = Source->queue->buffer; + } + else + Source->state = AL_PLAYING; + + // Check if an Offset has been set + if(Source->lOffset) + ApplyOffset(Source); + + if(Source->BuffersPlayed == 0 && Source->position == 0 && + Source->position_fraction == 0) + Source->FirstStart = AL_TRUE; + else + Source->FirstStart = AL_FALSE; + + // If device is disconnected, go right to stopped + if(!Context->Device->Connected) + { + Source->state = AL_STOPPED; + Source->BuffersPlayed = Source->BuffersInQueue; + Source->position = 0; + Source->position_fraction = 0; + } + else + { + for(j = 0;j < Context->ActiveSourceCount;j++) + { + if(Context->ActiveSources[j] == Source) + break; + } + if(j == Context->ActiveSourceCount) + Context->ActiveSources[Context->ActiveSourceCount++] = Source; + } + } + +done: + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) +{ + alSourcePausev(1, &source); +} + +AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) +{ + ALCcontext *Context; + ALsource *Source; + ALsizei i; + + Context = GetContextSuspended(); + if(!Context) return; + + if(!sources) + { + alSetError(Context, AL_INVALID_VALUE); + goto done; + } + + // Check all the Sources are valid + for(i = 0;i < n;i++) + { + if(!LookupSource(Context->SourceMap, sources[i])) + { + alSetError(Context, AL_INVALID_NAME); + goto done; + } + } + + for(i = 0;i < n;i++) + { + Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]); + if(Source->state == AL_PLAYING) + Source->state = AL_PAUSED; + } + +done: + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) +{ + alSourceStopv(1, &source); +} + +AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) +{ + ALCcontext *Context; + ALsource *Source; + ALsizei i; + + Context = GetContextSuspended(); + if(!Context) return; + + if(!sources) + { + alSetError(Context, AL_INVALID_VALUE); + goto done; + } + + // Check all the Sources are valid + for(i = 0;i < n;i++) + { + if(!LookupSource(Context->SourceMap, sources[i])) + { + alSetError(Context, AL_INVALID_NAME); + goto done; + } + } + + for(i = 0;i < n;i++) + { + Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]); + if(Source->state != AL_INITIAL) + { + Source->state = AL_STOPPED; + Source->BuffersPlayed = Source->BuffersInQueue; + } + Source->lOffset = 0; + } + +done: + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) +{ + alSourceRewindv(1, &source); +} + +AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) +{ + ALCcontext *Context; + ALsource *Source; + ALsizei i; + + Context = GetContextSuspended(); + if(!Context) return; + + if(!sources) + { + alSetError(Context, AL_INVALID_VALUE); + goto done; + } + + // Check all the Sources are valid + for(i = 0;i < n;i++) + { + if(!LookupSource(Context->SourceMap, sources[i])) + { + alSetError(Context, AL_INVALID_NAME); + goto done; + } + } + + for(i = 0;i < n;i++) + { + Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]); + if(Source->state != AL_INITIAL) + { + Source->state = AL_INITIAL; + Source->position = 0; + Source->position_fraction = 0; + Source->BuffersPlayed = 0; + if(Source->queue) + Source->Buffer = Source->queue->buffer; + } + Source->lOffset = 0; + } + +done: + ProcessContext(Context); +} + + +AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers) +{ + ALCcontext *Context; + ALCdevice *device; + ALsource *Source; + ALbuffer *buffer; + ALsizei i; + ALbufferlistitem *BufferListStart; + ALbufferlistitem *BufferList; + ALboolean HadFormat; + ALint Frequency; + ALint Format; + + if(n == 0) + return; + + Context = GetContextSuspended(); + if(!Context) return; + + // Check that all buffers are valid or zero and that the source is valid + + // Check that this is a valid source + if((Source=LookupSource(Context->SourceMap, source)) == NULL) + { + alSetError(Context, AL_INVALID_NAME); + goto done; + } + + // Check that this is not a STATIC Source + if(Source->lSourceType == AL_STATIC) + { + // Invalid Source Type (can't queue on a Static Source) + alSetError(Context, AL_INVALID_OPERATION); + goto done; + } + + device = Context->Device; + + Frequency = -1; + Format = -1; + HadFormat = AL_FALSE; + + // Check existing Queue (if any) for a valid Buffers and get its frequency and format + BufferList = Source->queue; + while(BufferList) + { + if(BufferList->buffer) + { + Frequency = BufferList->buffer->frequency; + Format = BufferList->buffer->format; + HadFormat = AL_TRUE; + break; + } + BufferList = BufferList->next; + } + + for(i = 0;i < n;i++) + { + if(!buffers[i]) + continue; + + if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL) + { + alSetError(Context, AL_INVALID_NAME); + goto done; + } + + if(Frequency == -1 && Format == -1) + { + Frequency = buffer->frequency; + Format = buffer->format; + } + else if(Frequency != buffer->frequency || Format != buffer->format) + { + alSetError(Context, AL_INVALID_OPERATION); + goto done; + } + } + + // Change Source Type + Source->lSourceType = AL_STREAMING; + + buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]); + + // All buffers are valid - so add them to the list + BufferListStart = malloc(sizeof(ALbufferlistitem)); + BufferListStart->buffer = buffer; + BufferListStart->next = NULL; + + // Increment reference counter for buffer + if(buffer) buffer->refcount++; + + BufferList = BufferListStart; + + for(i = 1;i < n;i++) + { + buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]); + + BufferList->next = malloc(sizeof(ALbufferlistitem)); + BufferList->next->buffer = buffer; + BufferList->next->next = NULL; + + // Increment reference counter for buffer + if(buffer) buffer->refcount++; + + BufferList = BufferList->next; + } + + if(Source->queue == NULL) + { + Source->queue = BufferListStart; + // Update Current Buffer + Source->Buffer = BufferListStart->buffer; + } + else + { + // Find end of queue + BufferList = Source->queue; + while(BufferList->next != NULL) + BufferList = BufferList->next; + + BufferList->next = BufferListStart; + } + + // Update number of buffers in queue + Source->BuffersInQueue += n; + // If no previous format, mark the source dirty now that it may have one + if(!HadFormat) + Source->NeedsUpdate = AL_TRUE; + +done: + ProcessContext(Context); +} + + +// Implementation assumes that n is the number of buffers to be removed from the queue and buffers is +// an array of buffer IDs that are to be filled with the names of the buffers removed +AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers ) +{ + ALCcontext *Context; + ALsource *Source; + ALsizei i; + ALbufferlistitem *BufferList; + + if(n == 0) + return; + + Context = GetContextSuspended(); + if(!Context) return; + + if((Source=LookupSource(Context->SourceMap, source)) == NULL) + { + alSetError(Context, AL_INVALID_NAME); + goto done; + } + + if(Source->bLooping || Source->lSourceType != AL_STREAMING || + (ALuint)n > Source->BuffersPlayed) + { + // Some buffers can't be unqueue because they have not been processed + alSetError(Context, AL_INVALID_VALUE); + goto done; + } + + for(i = 0;i < n;i++) + { + BufferList = Source->queue; + Source->queue = BufferList->next; + + if(BufferList->buffer) + { + // Record name of buffer + buffers[i] = BufferList->buffer->buffer; + // Decrement buffer reference counter + BufferList->buffer->refcount--; + } + else + buffers[i] = 0; + + // Release memory for buffer list item + free(BufferList); + Source->BuffersInQueue--; + } + + if(Source->state != AL_PLAYING) + { + if(Source->queue) + Source->Buffer = Source->queue->buffer; + else + Source->Buffer = NULL; + } + Source->BuffersPlayed -= n; + +done: + ProcessContext(Context); +} + + +static ALvoid InitSourceParams(ALsource *Source) +{ + Source->flInnerAngle = 360.0f; + Source->flOuterAngle = 360.0f; + Source->flPitch = 1.0f; + Source->vPosition[0] = 0.0f; + Source->vPosition[1] = 0.0f; + Source->vPosition[2] = 0.0f; + Source->vOrientation[0] = 0.0f; + Source->vOrientation[1] = 0.0f; + Source->vOrientation[2] = 0.0f; + Source->vVelocity[0] = 0.0f; + Source->vVelocity[1] = 0.0f; + Source->vVelocity[2] = 0.0f; + Source->flRefDistance = 1.0f; + Source->flMaxDistance = FLT_MAX; + Source->flRollOffFactor = 1.0f; + Source->bLooping = AL_FALSE; + Source->flGain = 1.0f; + Source->flMinGain = 0.0f; + Source->flMaxGain = 1.0f; + Source->flOuterGain = 0.0f; + Source->OuterGainHF = 1.0f; + + Source->DryGainHFAuto = AL_TRUE; + Source->WetGainAuto = AL_TRUE; + Source->WetGainHFAuto = AL_TRUE; + Source->AirAbsorptionFactor = 0.0f; + Source->RoomRolloffFactor = 0.0f; + Source->DopplerFactor = 1.0f; + + Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED; + + Source->Resampler = DefaultResampler; + + Source->state = AL_INITIAL; + Source->lSourceType = AL_UNDETERMINED; + + Source->NeedsUpdate = AL_TRUE; + + Source->Buffer = NULL; +} + + +/* + GetSourceOffset + + Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds) + The offset is relative to the start of the queue (not the start of the current buffer) +*/ +static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen) +{ + ALbufferlistitem *BufferList; + ALbuffer *Buffer = NULL; + ALfloat BufferFreq; + ALint Channels, Bytes; + ALuint readPos, writePos; + ALenum OriginalFormat; + ALuint TotalBufferDataSize; + ALuint i; + + // Find the first non-NULL Buffer in the Queue + BufferList = Source->queue; + while(BufferList) + { + if(BufferList->buffer) + { + Buffer = BufferList->buffer; + break; + } + BufferList = BufferList->next; + } + + if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer) + { + offset[0] = 0.0; + offset[1] = 0.0; + return; + } + + // Get Current Buffer Size and frequency (in milliseconds) + BufferFreq = (ALfloat)Buffer->frequency; + OriginalFormat = Buffer->eOriginalFormat; + Channels = aluChannelsFromFormat(Buffer->format); + Bytes = aluBytesFromFormat(Buffer->format); + + // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer) + readPos = Source->position * Channels * Bytes; + // Add byte length of any processed buffers in the queue + TotalBufferDataSize = 0; + BufferList = Source->queue; + for(i = 0;BufferList;i++) + { + if(BufferList->buffer) + { + if(i < Source->BuffersPlayed) + readPos += BufferList->buffer->size; + TotalBufferDataSize += BufferList->buffer->size; + } + BufferList = BufferList->next; + } + if(Source->state == AL_PLAYING) + writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes); + else + writePos = readPos; + + if(Source->bLooping) + { + readPos %= TotalBufferDataSize; + writePos %= TotalBufferDataSize; + } + else + { + // Clamp positions to TotalBufferDataSize + if(readPos > TotalBufferDataSize) + readPos = TotalBufferDataSize; + if(writePos > TotalBufferDataSize) + writePos = TotalBufferDataSize; + } + + switch(name) + { + case AL_SEC_OFFSET: + offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq); + offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq); + break; + case AL_SAMPLE_OFFSET: + case AL_SAMPLE_RW_OFFSETS_EXT: + offset[0] = (ALdouble)(readPos / (Channels * Bytes)); + offset[1] = (ALdouble)(writePos / (Channels * Bytes)); + break; + case AL_BYTE_OFFSET: + case AL_BYTE_RW_OFFSETS_EXT: + // Take into account the original format of the Buffer + if((OriginalFormat == AL_FORMAT_MONO_IMA4) || + (OriginalFormat == AL_FORMAT_STEREO_IMA4)) + { + // Round down to nearest ADPCM block + offset[0] = (ALdouble)((readPos / (65 * Bytes * Channels)) * 36 * Channels); + if(Source->state == AL_PLAYING) + { + // Round up to nearest ADPCM block + offset[1] = (ALdouble)(((writePos + (65 * Bytes * Channels) - 1) / (65 * Bytes * Channels)) * 36 * Channels); + } + else + offset[1] = offset[0]; + } + else if(OriginalFormat == AL_FORMAT_MONO_MULAW || + OriginalFormat == AL_FORMAT_STEREO_MULAW || + OriginalFormat == AL_FORMAT_QUAD_MULAW || + OriginalFormat == AL_FORMAT_51CHN_MULAW || + OriginalFormat == AL_FORMAT_61CHN_MULAW || + OriginalFormat == AL_FORMAT_71CHN_MULAW) + { + offset[0] = (ALdouble)(readPos / Bytes * 1); + offset[1] = (ALdouble)(writePos / Bytes * 1); + } + else if(OriginalFormat == AL_FORMAT_REAR_MULAW) + { + offset[0] = (ALdouble)(readPos / 2 / Bytes * 1); + offset[1] = (ALdouble)(writePos / 2 / Bytes * 1); + } + else if(OriginalFormat == AL_FORMAT_REAR8) + { + offset[0] = (ALdouble)(readPos / 2 / Bytes * 1); + offset[1] = (ALdouble)(writePos / 2 / Bytes * 1); + } + else if(OriginalFormat == AL_FORMAT_REAR16) + { + offset[0] = (ALdouble)(readPos / 2 / Bytes * 2); + offset[1] = (ALdouble)(writePos / 2 / Bytes * 2); + } + else if(OriginalFormat == AL_FORMAT_REAR32) + { + offset[0] = (ALdouble)(readPos / 2 / Bytes * 4); + offset[1] = (ALdouble)(writePos / 2 / Bytes * 4); + } + else + { + ALuint OrigBytes = aluBytesFromFormat(OriginalFormat); + offset[0] = (ALdouble)(readPos / Bytes * OrigBytes); + offset[1] = (ALdouble)(writePos / Bytes * OrigBytes); + } + break; + } +} + + +/* + ApplyOffset + + Apply a playback offset to the Source. This function will update the queue (to correctly + mark buffers as 'pending' or 'processed' depending upon the new offset. +*/ +static ALboolean ApplyOffset(ALsource *Source) +{ + ALbufferlistitem *BufferList; + ALbuffer *Buffer; + ALint lBufferSize, lTotalBufferSize; + ALint BuffersPlayed; + ALint lByteOffset; + + // Get true byte offset + lByteOffset = GetByteOffset(Source); + + // If the offset is invalid, don't apply it + if(lByteOffset == -1) + return AL_FALSE; + + // Sort out the queue (pending and processed states) + BufferList = Source->queue; + lTotalBufferSize = 0; + BuffersPlayed = 0; + + while(BufferList) + { + Buffer = BufferList->buffer; + lBufferSize = Buffer ? Buffer->size : 0; + + if(lTotalBufferSize+lBufferSize <= lByteOffset) + { + // Offset is past this buffer so increment BuffersPlayed + BuffersPlayed++; + } + else if(lTotalBufferSize <= lByteOffset) + { + // Offset is within this buffer + // Set Current Buffer + Source->Buffer = BufferList->buffer; + Source->BuffersPlayed = BuffersPlayed; + + // SW Mixer Positions are in Samples + Source->position = (lByteOffset - lTotalBufferSize) / + aluFrameSizeFromFormat(Buffer->format); + return AL_TRUE; + } + + // Increment the TotalBufferSize + lTotalBufferSize += lBufferSize; + + // Move on to next buffer in the Queue + BufferList = BufferList->next; + } + // Offset is out of range of the buffer queue + return AL_FALSE; +} + + +/* + GetByteOffset + + Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond + offset supplied by the application). This takes into account the fact that the buffer format + may have been modifed by AL (e.g 8bit samples are converted to float) +*/ +static ALint GetByteOffset(ALsource *Source) +{ + ALbuffer *Buffer = NULL; + ALbufferlistitem *BufferList; + ALfloat BufferFreq; + ALint Channels, Bytes; + ALint ByteOffset = -1; + + // Find the first non-NULL Buffer in the Queue + BufferList = Source->queue; + while(BufferList) + { + if(BufferList->buffer) + { + Buffer = BufferList->buffer; + break; + } + BufferList = BufferList->next; + } + + if(!Buffer) + { + Source->lOffset = 0; + return -1; + } + + BufferFreq = ((ALfloat)Buffer->frequency); + Channels = aluChannelsFromFormat(Buffer->format); + Bytes = aluBytesFromFormat(Buffer->format); + + // Determine the ByteOffset (and ensure it is block aligned) + switch(Source->lOffsetType) + { + case AL_BYTE_OFFSET: + // Take into consideration the original format + ByteOffset = FramesFromBytes(Source->lOffset, Buffer->eOriginalFormat, + Channels); + ByteOffset *= Channels * Bytes; + break; + + case AL_SAMPLE_OFFSET: + ByteOffset = Source->lOffset * Channels * Bytes; + break; + + case AL_SEC_OFFSET: + // Note - lOffset is internally stored as Milliseconds + ByteOffset = (ALint)(Source->lOffset / 1000.0f * BufferFreq); + ByteOffset *= Channels * Bytes; + break; + } + // Clear Offset + Source->lOffset = 0; + + return ByteOffset; +} + +static ALint FramesFromBytes(ALint offset, ALenum format, ALint channels) +{ + if(format==AL_FORMAT_MONO_IMA4 || format==AL_FORMAT_STEREO_IMA4) + { + // Round down to nearest ADPCM block + offset /= 36 * channels; + // Multiply by compression rate (65 sample frames per block) + offset *= 65; + } + else if(format==AL_FORMAT_MONO_MULAW || format==AL_FORMAT_STEREO_MULAW || + format==AL_FORMAT_QUAD_MULAW || format==AL_FORMAT_51CHN_MULAW || + format==AL_FORMAT_61CHN_MULAW || format==AL_FORMAT_71CHN_MULAW) + { + /* muLaw has 1 byte per sample */ + offset /= 1 * channels; + } + else if(format == AL_FORMAT_REAR_MULAW) + { + /* Rear is 2 channels */ + offset /= 1 * 2; + } + else if(format == AL_FORMAT_REAR8) + offset /= 1 * 2; + else if(format == AL_FORMAT_REAR16) + offset /= 2 * 2; + else if(format == AL_FORMAT_REAR32) + offset /= 4 * 2; + else + { + ALuint bytes = aluBytesFromFormat(format); + offset /= bytes * channels; + } + return offset; +} + + +ALvoid ReleaseALSources(ALCcontext *Context) +{ + ALsizei pos; + ALuint j; + for(pos = 0;pos < Context->SourceMap.size;pos++) + { + ALsource *temp = Context->SourceMap.array[pos].value; + Context->SourceMap.array[pos].value = NULL; + + // For each buffer in the source's queue, decrement its reference counter and remove it + while(temp->queue != NULL) + { + ALbufferlistitem *BufferList = temp->queue; + // Decrement buffer's reference counter + if(BufferList->buffer != NULL) + BufferList->buffer->refcount--; + // Update queue to point to next element in list + temp->queue = BufferList->next; + // Release memory allocated for buffer list item + free(BufferList); + } + + for(j = 0;j < MAX_SENDS;++j) + { + if(temp->Send[j].Slot) + temp->Send[j].Slot->refcount--; + } + + // Release source structure + ALTHUNK_REMOVEENTRY(temp->source); + memset(temp, 0, sizeof(ALsource)); + free(temp); + } +} diff --git a/project/jni/openal/src/OpenAL32/alState.c b/project/jni/openal/src/OpenAL32/alState.c new file mode 100644 index 000000000..953b1a172 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/alState.c @@ -0,0 +1,661 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include "alMain.h" +#include "AL/alc.h" +#include "AL/alext.h" +#include "alError.h" +#include "alSource.h" +#include "alState.h" +#include "alDatabuffer.h" + +static const ALchar alVendor[] = "OpenAL Community"; +static const ALchar alVersion[] = "1.1 ALSOFT "ALSOFT_VERSION; +static const ALchar alRenderer[] = "OpenAL Soft"; + +// Error Messages +static const ALchar alNoError[] = "No Error"; +static const ALchar alErrInvalidName[] = "Invalid Name"; +static const ALchar alErrInvalidEnum[] = "Invalid Enum"; +static const ALchar alErrInvalidValue[] = "Invalid Value"; +static const ALchar alErrInvalidOp[] = "Invalid Operation"; +static const ALchar alErrOutOfMemory[] = "Out of Memory"; + +AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) +{ + ALCcontext *Context; + ALboolean updateSources = AL_FALSE; + + Context = GetContextSuspended(); + if(!Context) return; + + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + Context->SourceDistanceModel = AL_TRUE; + updateSources = AL_TRUE; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + + if(updateSources) + { + ALsizei pos; + for(pos = 0;pos < Context->SourceMap.size;pos++) + { + ALsource *source = Context->SourceMap.array[pos].value; + source->NeedsUpdate = AL_TRUE; + } + } + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) +{ + ALCcontext *Context; + ALboolean updateSources = AL_FALSE; + + Context = GetContextSuspended(); + if(!Context) return; + + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + Context->SourceDistanceModel = AL_FALSE; + updateSources = AL_TRUE; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + + if(updateSources) + { + ALsizei pos; + for(pos = 0;pos < Context->SourceMap.size;pos++) + { + ALsource *source = Context->SourceMap.array[pos].value; + source->NeedsUpdate = AL_TRUE; + } + } + + ProcessContext(Context); +} + +AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) +{ + ALCcontext *Context; + ALboolean value=AL_FALSE; + + Context = GetContextSuspended(); + if(!Context) return AL_FALSE; + + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + value = Context->SourceDistanceModel; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + + ProcessContext(Context); + + return value; +} + +AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) +{ + ALCcontext *Context; + ALboolean value=AL_FALSE; + + Context = GetContextSuspended(); + if(!Context) return AL_FALSE; + + switch(pname) + { + case AL_DOPPLER_FACTOR: + if(Context->DopplerFactor != 0.0f) + value = AL_TRUE; + break; + + case AL_DOPPLER_VELOCITY: + if(Context->DopplerVelocity != 0.0f) + value = AL_TRUE; + break; + + case AL_DISTANCE_MODEL: + if(Context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED) + value = AL_TRUE; + break; + + case AL_SPEED_OF_SOUND: + if(Context->flSpeedOfSound != 0.0f) + value = AL_TRUE; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + + ProcessContext(Context); + + return value; +} + +AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) +{ + ALCcontext *Context; + ALdouble value = 0.0; + + Context = GetContextSuspended(); + if(!Context) return 0.0; + + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = (double)Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = (double)Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (double)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = (double)Context->flSpeedOfSound; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + + ProcessContext(Context); + + return value; +} + +AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) +{ + ALCcontext *Context; + ALfloat value = 0.0f; + + Context = GetContextSuspended(); + if(!Context) return 0.0f; + + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (float)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = Context->flSpeedOfSound; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + + ProcessContext(Context); + + return value; +} + +AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) +{ + ALCcontext *Context; + ALint value = 0; + + Context = GetContextSuspended(); + if(!Context) return 0; + + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = (ALint)Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = (ALint)Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (ALint)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = (ALint)Context->flSpeedOfSound; + break; + + case AL_SAMPLE_SOURCE_EXT: + if(Context->SampleSource) + value = (ALint)Context->SampleSource->databuffer; + else + value = 0; + break; + + case AL_SAMPLE_SINK_EXT: + if(Context->SampleSink) + value = (ALint)Context->SampleSink->databuffer; + else + value = 0; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + + ProcessContext(Context); + + return value; +} + +AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname,ALboolean *data) +{ + ALCcontext *Context; + + Context = GetContextSuspended(); + if(!Context) return; + + if(data) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + *data = (ALboolean)((Context->DopplerFactor != 0.0f) ? AL_TRUE : AL_FALSE); + break; + + case AL_DOPPLER_VELOCITY: + *data = (ALboolean)((Context->DopplerVelocity != 0.0f) ? AL_TRUE : AL_FALSE); + break; + + case AL_DISTANCE_MODEL: + *data = (ALboolean)((Context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED) ? AL_TRUE : AL_FALSE); + break; + + case AL_SPEED_OF_SOUND: + *data = (ALboolean)((Context->flSpeedOfSound != 0.0f) ? AL_TRUE : AL_FALSE); + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + { + // data is a NULL pointer + alSetError(Context, AL_INVALID_VALUE); + } + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname,ALdouble *data) +{ + ALCcontext *Context; + + Context = GetContextSuspended(); + if(!Context) return; + + if(data) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + *data = (double)Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + *data = (double)Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + *data = (double)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + *data = (double)Context->flSpeedOfSound; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + { + // data is a NULL pointer + alSetError(Context, AL_INVALID_VALUE); + } + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname,ALfloat *data) +{ + ALCcontext *Context; + + Context = GetContextSuspended(); + if(!Context) return; + + if(data) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + *data = Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + *data = Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + *data = (float)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + *data = Context->flSpeedOfSound; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + { + // data is a NULL pointer + alSetError(Context, AL_INVALID_VALUE); + } + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname,ALint *data) +{ + ALCcontext *Context; + + Context = GetContextSuspended(); + if(!Context) return; + + if(data) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + *data = (ALint)Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + *data = (ALint)Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + *data = (ALint)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + *data = (ALint)Context->flSpeedOfSound; + break; + + case AL_SAMPLE_SOURCE_EXT: + if(Context->SampleSource) + *data = (ALint)Context->SampleSource->databuffer; + else + *data = 0; + break; + + case AL_SAMPLE_SINK_EXT: + if(Context->SampleSink) + *data = (ALint)Context->SampleSink->databuffer; + else + *data = 0; + break; + + default: + alSetError(Context, AL_INVALID_ENUM); + break; + } + } + else + { + // data is a NULL pointer + alSetError(Context, AL_INVALID_VALUE); + } + + ProcessContext(Context); +} + +AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname) +{ + const ALchar *value; + ALCcontext *pContext; + + pContext = GetContextSuspended(); + if(!pContext) return NULL; + + switch(pname) + { + case AL_VENDOR: + value=alVendor; + break; + + case AL_VERSION: + value=alVersion; + break; + + case AL_RENDERER: + value=alRenderer; + break; + + case AL_EXTENSIONS: + value=pContext->ExtensionList;//alExtensions; + break; + + case AL_NO_ERROR: + value=alNoError; + break; + + case AL_INVALID_NAME: + value=alErrInvalidName; + break; + + case AL_INVALID_ENUM: + value=alErrInvalidEnum; + break; + + case AL_INVALID_VALUE: + value=alErrInvalidValue; + break; + + case AL_INVALID_OPERATION: + value=alErrInvalidOp; + break; + + case AL_OUT_OF_MEMORY: + value=alErrOutOfMemory; + break; + + default: + value=NULL; + alSetError(pContext, AL_INVALID_ENUM); + break; + } + + ProcessContext(pContext); + + return value; +} + +AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) +{ + ALCcontext *Context; + ALboolean updateSources = AL_FALSE; + + Context = GetContextSuspended(); + if(!Context) return; + + if(value >= 0.0f) + { + Context->DopplerFactor = value; + updateSources = AL_TRUE; + } + else + alSetError(Context, AL_INVALID_VALUE); + + // Force updating the sources for these parameters, since even head- + // relative sources are affected + if(updateSources) + { + ALsizei pos; + for(pos = 0;pos < Context->SourceMap.size;pos++) + { + ALsource *source = Context->SourceMap.array[pos].value; + source->NeedsUpdate = AL_TRUE; + } + } + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) +{ + ALCcontext *Context; + ALboolean updateSources = AL_FALSE; + + Context = GetContextSuspended(); + if(!Context) return; + + if(value > 0.0f) + { + Context->DopplerVelocity=value; + updateSources = AL_TRUE; + } + else + alSetError(Context, AL_INVALID_VALUE); + + if(updateSources) + { + ALsizei pos; + for(pos = 0;pos < Context->SourceMap.size;pos++) + { + ALsource *source = Context->SourceMap.array[pos].value; + source->NeedsUpdate = AL_TRUE; + } + } + + ProcessContext(Context); +} + +AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat flSpeedOfSound) +{ + ALCcontext *pContext; + ALboolean updateSources = AL_FALSE; + + pContext = GetContextSuspended(); + if(!pContext) return; + + if(flSpeedOfSound > 0.0f) + { + pContext->flSpeedOfSound = flSpeedOfSound; + updateSources = AL_TRUE; + } + else + alSetError(pContext, AL_INVALID_VALUE); + + if(updateSources) + { + ALsizei pos; + for(pos = 0;pos < pContext->SourceMap.size;pos++) + { + ALsource *source = pContext->SourceMap.array[pos].value; + source->NeedsUpdate = AL_TRUE; + } + } + + ProcessContext(pContext); +} + +AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) +{ + ALCcontext *Context; + ALboolean updateSources = AL_FALSE; + + Context = GetContextSuspended(); + if(!Context) return; + + switch(value) + { + case AL_NONE: + case AL_INVERSE_DISTANCE: + case AL_INVERSE_DISTANCE_CLAMPED: + case AL_LINEAR_DISTANCE: + case AL_LINEAR_DISTANCE_CLAMPED: + case AL_EXPONENT_DISTANCE: + case AL_EXPONENT_DISTANCE_CLAMPED: + Context->DistanceModel = value; + updateSources = !Context->SourceDistanceModel; + break; + + default: + alSetError(Context, AL_INVALID_VALUE); + break; + } + + if(updateSources) + { + ALsizei pos; + for(pos = 0;pos < Context->SourceMap.size;pos++) + { + ALsource *source = Context->SourceMap.array[pos].value; + source->NeedsUpdate = AL_TRUE; + } + } + + ProcessContext(Context); +} diff --git a/project/jni/openal/src/OpenAL32/alThunk.c b/project/jni/openal/src/OpenAL32/alThunk.c new file mode 100644 index 000000000..08b80b067 --- /dev/null +++ b/project/jni/openal/src/OpenAL32/alThunk.c @@ -0,0 +1,111 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include + +#include "alMain.h" +#include "alThunk.h" + +typedef struct { + ALvoid *ptr; + ALboolean InUse; +} ThunkEntry; + +static ThunkEntry *g_ThunkArray; +static ALuint g_ThunkArraySize; + +static CRITICAL_SECTION g_ThunkLock; + +void alThunkInit(void) +{ + InitializeCriticalSection(&g_ThunkLock); + g_ThunkArraySize = 1; + g_ThunkArray = calloc(1, g_ThunkArraySize * sizeof(ThunkEntry)); +} + +void alThunkExit(void) +{ + free(g_ThunkArray); + g_ThunkArray = NULL; + g_ThunkArraySize = 0; + DeleteCriticalSection(&g_ThunkLock); +} + +ALuint alThunkAddEntry(ALvoid *ptr) +{ + ALuint index; + + EnterCriticalSection(&g_ThunkLock); + + for(index = 0;index < g_ThunkArraySize;index++) + { + if(g_ThunkArray[index].InUse == AL_FALSE) + break; + } + + if(index == g_ThunkArraySize) + { + ThunkEntry *NewList; + + NewList = realloc(g_ThunkArray, g_ThunkArraySize*2 * sizeof(ThunkEntry)); + if(!NewList) + { + LeaveCriticalSection(&g_ThunkLock); + AL_PRINT("Realloc failed to increase to %u enties!\n", g_ThunkArraySize*2); + return 0; + } + memset(&NewList[g_ThunkArraySize], 0, g_ThunkArraySize*sizeof(ThunkEntry)); + g_ThunkArraySize *= 2; + g_ThunkArray = NewList; + } + + g_ThunkArray[index].ptr = ptr; + g_ThunkArray[index].InUse = AL_TRUE; + + LeaveCriticalSection(&g_ThunkLock); + + return index+1; +} + +void alThunkRemoveEntry(ALuint index) +{ + EnterCriticalSection(&g_ThunkLock); + + if(index > 0 && index <= g_ThunkArraySize) + g_ThunkArray[index-1].InUse = AL_FALSE; + + LeaveCriticalSection(&g_ThunkLock); +} + +ALvoid *alThunkLookupEntry(ALuint index) +{ + ALvoid *ptr = NULL; + + EnterCriticalSection(&g_ThunkLock); + + if(index > 0 && index <= g_ThunkArraySize) + ptr = g_ThunkArray[index-1].ptr; + + LeaveCriticalSection(&g_ThunkLock); + + return ptr; +} diff --git a/project/jni/openal/src/config.h b/project/jni/openal/src/config.h new file mode 100644 index 000000000..284cdd644 --- /dev/null +++ b/project/jni/openal/src/config.h @@ -0,0 +1,82 @@ +#ifndef CONFIG_H +#define CONFIG_H + +/* Define to the library version */ +#define ALSOFT_VERSION "1.0.0" + +/* Define if we have the PulseAudio backend */ +#define HAVE_ANDROID 1 + +/* Define if we have dlfcn.h */ +#define HAVE_DLFCN_H 1 + +/* Define if we have the stat function */ +#define HAVE_STAT 1 + +/* Define if we have the powf function */ +#define HAVE_POWF + +/* Define if we have the sqrtf function */ +#define HAVE_SQRTF + +/* Define if we have the acosf function */ +#define HAVE_ACOSF + +/* Define if we have the atanf function */ +#define HAVE_ATANF + +/* Define if we have the fabsf function */ +#define HAVE_FABSF + +/* Define if we have the strtof function */ +#define HAVE_STRTOF + +/* Define if we have stdint.h */ +#define HAVE_STDINT_H + +/* Define if we have the __int64 type */ +#define HAVE___INT64 + +/* Define to the size of a long int type */ +#define SIZEOF_LONG 4 + +/* Define to the size of a long long int type */ +#define SIZEOF_LONG_LONG 8 + +/* Define to the size of an unsigned int type */ +#define SIZEOF_UINT 4 + +/* Define to the size of a void pointer type */ +#define SIZEOF_VOIDP 4 + +/* Define if we have GCC's destructor attribute */ +#define HAVE_GCC_DESTRUCTOR 1 + +/* Define if we have GCC's format attribute */ +#define HAVE_GCC_FORMAT 1 + +/* Define if we have pthread_np.h */ +/* +#define HAVE_PTHREAD_NP_H +*/ + +/* Define if we have float.h */ +/* +#define HAVE_FLOAT_H +*/ + +/* Define if we have fenv.h */ +#define HAVE_FENV_H 1 + +/* Define if we have fesetround() */ +#define HAVE_FESETROUND 1 + +/* Define if we have _controlfp() */ +/* +#define HAVE__CONTROLFP +*/ + +/* Define if we have pthread_setschedparam() */ +#define HAVE_PTHREAD_SETSCHEDPARAM 1 + +#endif diff --git a/project/jni/sdl_main/sdl_main.c b/project/jni/sdl_main/sdl_main.c index d6e8a545b..76e2ddf7d 100644 --- a/project/jni/sdl_main/sdl_main.c +++ b/project/jni/sdl_main/sdl_main.c @@ -89,6 +89,11 @@ JAVA_EXPORT_NAME(DemoRenderer_nativeInit) ( JNIEnv* env, jobject thiz, jstring for( i = 0; i < argc; i++ ) __android_log_print(ANDROID_LOG_INFO, "libSDL", "param %d = \"%s\"", i, argv[i]); + + + // Redirect stdout and stderr - otherwise it crashes on Smartq V7 + freopen("/dev/null", "w", stdout); + freopen("/dev/null", "w", stderr); main( argc, argv );