From 33737e8c99061c62aad69913b893b5c237a0353c Mon Sep 17 00:00:00 2001 From: crt0mega Date: Wed, 17 Feb 2021 17:37:53 +0100 Subject: [PATCH] Initial commit and fixing/working around compiler errors --- COPYING | 437 ++++++++++++++++++ ChangeLog | 64 +++ README | 29 ++ etc/README | 86 ++++ etc/speakers-fivepoint-a | 8 + etc/speakers-fivepoint-b | 8 + etc/speakers-fivepoint-c | 8 + etc/speakers-fivepoint-d | 8 + etc/speakers-mono | 8 + etc/speakers-quadraphonic | 8 + etc/speakers-sevenpoint-a | 8 + etc/speakers-sevenpoint-b | 8 + etc/speakers-sevenpoint-c | 8 + etc/speakers-stereo | 8 + include/AL/al.h | 642 ++++++++++++++++++++++++++ include/AL/alc.h | 163 +++++++ include/AL/alctypes.h | 121 +++++ include/AL/alext.h | 76 +++ include/AL/alexttypes.h | 161 +++++++ include/AL/altypes.h | 484 ++++++++++++++++++++ include/AL/alu.h | 61 +++ include/AL/alut.h | 101 ++++ include/AL/aluttypes.h | 6 + include/AL/alutypes.h | 5 + src/Makefile | 62 +++ src/al_able.c | 38 ++ src/al_buffer.c | 462 +++++++++++++++++++ src/al_buffer.h | 40 ++ src/al_distance.c | 93 ++++ src/al_doppler.c | 55 +++ src/al_error.c | 37 ++ src/al_error.h | 42 ++ src/al_ext.c | 140 ++++++ src/al_listener.c | 300 ++++++++++++ src/al_listener.h | 37 ++ src/al_play.c | 642 ++++++++++++++++++++++++++ src/al_source.c | 939 ++++++++++++++++++++++++++++++++++++++ src/al_source.h | 81 ++++ src/al_state.c | 216 +++++++++ src/al_vector.c | 64 +++ src/al_vector.h | 31 ++ src/alc_context.c | 292 ++++++++++++ src/alc_context.h | 62 +++ src/alc_device.c | 227 +++++++++ src/alc_device.h | 44 ++ src/alc_error.c | 39 ++ src/alc_error.h | 28 ++ src/alc_ext.c | 42 ++ src/alc_speaker.c | 91 ++++ src/alc_speaker.h | 37 ++ src/alc_state.c | 104 +++++ src/alut_main.c | 60 +++ src/alut_wav.c | 288 ++++++++++++ 53 files changed, 7109 insertions(+) create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 README create mode 100644 etc/README create mode 100644 etc/speakers-fivepoint-a create mode 100644 etc/speakers-fivepoint-b create mode 100644 etc/speakers-fivepoint-c create mode 100644 etc/speakers-fivepoint-d create mode 100644 etc/speakers-mono create mode 100644 etc/speakers-quadraphonic create mode 100644 etc/speakers-sevenpoint-a create mode 100644 etc/speakers-sevenpoint-b create mode 100644 etc/speakers-sevenpoint-c create mode 100644 etc/speakers-stereo create mode 100644 include/AL/al.h create mode 100644 include/AL/alc.h create mode 100644 include/AL/alctypes.h create mode 100644 include/AL/alext.h create mode 100644 include/AL/alexttypes.h create mode 100644 include/AL/altypes.h create mode 100644 include/AL/alu.h create mode 100644 include/AL/alut.h create mode 100644 include/AL/aluttypes.h create mode 100644 include/AL/alutypes.h create mode 100644 src/Makefile create mode 100644 src/al_able.c create mode 100644 src/al_buffer.c create mode 100644 src/al_buffer.h create mode 100644 src/al_distance.c create mode 100644 src/al_doppler.c create mode 100644 src/al_error.c create mode 100644 src/al_error.h create mode 100644 src/al_ext.c create mode 100644 src/al_listener.c create mode 100644 src/al_listener.h create mode 100644 src/al_play.c create mode 100644 src/al_source.c create mode 100644 src/al_source.h create mode 100644 src/al_state.c create mode 100644 src/al_vector.c create mode 100644 src/al_vector.h create mode 100644 src/alc_context.c create mode 100644 src/alc_context.h create mode 100644 src/alc_device.c create mode 100644 src/alc_device.h create mode 100644 src/alc_error.c create mode 100644 src/alc_error.h create mode 100644 src/alc_ext.c create mode 100644 src/alc_speaker.c create mode 100644 src/alc_speaker.h create mode 100644 src/alc_state.c create mode 100644 src/alut_main.c create mode 100644 src/alut_wav.c diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..191a97f --- /dev/null +++ b/COPYING @@ -0,0 +1,437 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e410129 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,64 @@ +Thu Jul 1 21:22:16 GMT 2004 C.J.Purnell (cjp@lost.org.uk) + + * Version 0.1.2 releaased. + + * Added a top level README with information about the + hw_params error message. + + * Added more example speaker configurations. + Put a description for each in the README. + + * It seems Audigy cards have twice the channels in the send + mixer controls. Added support for this. + + * Changed the way it looks for a compatable card. + Instead of looking for a card with a "emu10k1" pcm device. + It now looks for a card with a "EMU10K1 PCM Send Routing" + mixer control. + + * Removed float->int in the inner plackback loop. + Used 16.16 fixed point instead. + This should give us a speed increase. + + * Changed the default value for the doppler factor. + +Mon Jun 28 18:28:57 GMT 2004 C.J.Purnell (cjp@lost.org.uk) + + * Version 0.1.1 released. + + * Fixed buffering of 8bit mono data. + + * Fixed a bug in the matrix multiply function. + +Sun Jun 12 00:26:16 GMT 2004 C.J.Purnell (cjp@lost.org.uk) + + * Version 0.1.0 released. + + * Don't call snd_pcm_start() unless there is actually + some data to play. + +Fri Jun 11 23:29:45 GMT 2004 C.J.Purnell (cjp@lost.org.uk) + + * Version 0.0.4 released. + + * Much tweeking of plackback internals. + + * Added ALUT WAV file loading functions. + +Tue Jun 8 19:46:43 GMT 2004 C.J.Purnell (cjp@lost.org.uk) + + * Version 0.0.3 released. + + * Fixed speaker config file parsing. + + * Made thread safe. + +Thu Jun 4 07:39:00 GMT 2004 C.J.Purnell (cjp@lost.org.uk) + + * Version 0.0.2 released. + + * Removed some debugging output. + +Thu Jun 3 22:55:21 GMT 2004 C.J.Purnell (cjp@lost.org.uk) + + * Version 0.0.1 released. diff --git a/README b/README new file mode 100644 index 0000000..6deb87b --- /dev/null +++ b/README @@ -0,0 +1,29 @@ +The error: + +ALSA lib pcm_hw.c:324:(snd_pcm_hw_hw_params) SNDRV_PCM_IOCTL_HW_PARAMS failed: Cannot allocate memory + +can be safely ignored in most cases. It is just the application trying to +allocate more sources than there are free hardware resources to accomodate. + +This library can provide at most 21 sources. It may be more in the future. +Less sources will the avaiable if another application is doing audio playback. + +If you are using UT2004 you can supress this message most of the time by +modifying your ~/.ut2004/System/UT2004.ini as follows: + +[ALAudio.ALAudioSubsystem] +Channels=20 + + + +If on a Soundblaster Live, in your ~/.openal-speakers you have volumes set +for any more than the first two speakers you should manually zero the +following mixer controls: + +Wave Surround Playback Volume +Wave Center Playback Volume +Wave LFE Playback Volume + +You may not need to do this on an Audigy or Audigy2 but I've not been able to +test that. + diff --git a/etc/README b/etc/README new file mode 100644 index 0000000..cca261e --- /dev/null +++ b/etc/README @@ -0,0 +1,86 @@ +This directory contains example speaker configuration files. +To use one simple copy it to $HOME/.openal-speakers + +The format is simple: + +: + +where is a number indication which speaker: + +0: front left +1: front right +2: rear left +3: rear right +4: center +5: lfe +6: side left +7: side right + + is a per speaker gain control between 0.0 and 1.0. +Setting the gain to 0.0 disables output to the speaker. + + is the speaker position. + is forward, is up and is to the right. +Only the direction of this vector is used. + +Anything after a "#" is considered a comment. + +speakers-mono: + + This one is just simple example. + +speakers-stereo: + + This is the default configuration. If you are going to use this +you may as well not bother with a speakers file. + +speakers-quadraphonic: + + Fourpoint output. Each speaker placed in different corner of a square. + +speakers-fivepoint-a: + + This is what I'm told is the correct placement of speakers in a 5.1 +setup. The front speakers are 30° from the center speaker and the rear +speakers are 110° from the center speaker. This is very front biased. +Due to they way I calculate the speaker gain/volume sound behind you ends up +being very quiet. I know there are schemes I could use that would allow for +this but they don't seems to cope very well with the lack of above of below +speakers. + +speakers-fivepoint-b: + + This is the five speakers placed evenly around the listener, such +that they are all 72° from their neighbours. + +speakers-fivepoint-c: + + This has the front are rear speakers placed the same as for the +quadraphonic configuration with the addition of the front speaker. + +speakers-fivepoint-d: + + This has the speakers each placed 60° from their neighbours. The +speakers would be placed evenly around the listener in this configuration +if there was a single rear speaker. + +speakers-sevenpoint-a: + + I have no idea what the correct placement for 7.1 systems is. This +is with the front three speakers placed the same as the 5.1 setup. The +side speakers are placed 90° from the front. And the rear are placed at +60° from their neighbours. The end result is a configuration where +everything would be placed evenly around the listener if you take away the +front speaker. + +speakers-sevenpoint-b: + + This is the seven speakers placed evenly around the listener. +This has them all at some funny angle from their neighbours. + +speakers-sevenpoint-c: + + This has the front and rear speakers placed the same as for the +quadraphonic configuration. And the side speakers are placed 90° from the +front. The speakers would be placed evenly around the listener in this +configuration with the addition of a rear center speaker. diff --git a/etc/speakers-fivepoint-a b/etc/speakers-fivepoint-a new file mode 100644 index 0000000..b8ebab0 --- /dev/null +++ b/etc/speakers-fivepoint-a @@ -0,0 +1,8 @@ +0: 1 -0.5 0 0.8860254 +1: 1 0.5 0 0.8860254 +2: 1 -0.93969262 0 -0.34202014 +3: 1 0.93969262 0 -0.34202014 +4: 1 0 0 1 +5: 0 0 0 0 +6: 0 0 0 0 +7: 0 0 0 0 diff --git a/etc/speakers-fivepoint-b b/etc/speakers-fivepoint-b new file mode 100644 index 0000000..2d615dc --- /dev/null +++ b/etc/speakers-fivepoint-b @@ -0,0 +1,8 @@ +0: 1 -0.95105652 0 0.30916994 +1: 1 0.95105652 0 0.30916994 +2: 1 -0.58778525 0 -0.80901699 +3: 1 0.58778525 0 -0.80901699 +4: 1 0 0 1 +5: 0 0 0 0 +6: 0 0 0 0 +7: 0 0 0 0 diff --git a/etc/speakers-fivepoint-c b/etc/speakers-fivepoint-c new file mode 100644 index 0000000..d10b88b --- /dev/null +++ b/etc/speakers-fivepoint-c @@ -0,0 +1,8 @@ +0: 1 -0.70710678 0 0.70710678 +1: 1 0.70710678 0 0.70710678 +2: 1 -0.70710678 0 -0.70710678 +3: 1 0.70710678 0 -0.70710678 +4: 1 0 0 1 +5: 0 0 0 0 +6: 0 0 0 0 +7: 0 0 0 0 diff --git a/etc/speakers-fivepoint-d b/etc/speakers-fivepoint-d new file mode 100644 index 0000000..d723710 --- /dev/null +++ b/etc/speakers-fivepoint-d @@ -0,0 +1,8 @@ +0: 1 -0.8860254 0 0.5 +1: 1 0.8860254 0 0.5 +2: 1 -0.8860254 0 -0.5 +3: 1 0.8860254 0 -0.5 +4: 1 0 0 1 +5: 0 0 0 0 +6: 0 0 0 0 +7: 0 0 0 0 diff --git a/etc/speakers-mono b/etc/speakers-mono new file mode 100644 index 0000000..5624aa4 --- /dev/null +++ b/etc/speakers-mono @@ -0,0 +1,8 @@ +0: 1 0 0 0 +1: 1 0 0 0 +2: 0 0 0 0 +3: 0 0 0 0 +4: 0 0 0 0 +5: 0 0 0 0 +6: 0 0 0 0 +7: 0 0 0 0 diff --git a/etc/speakers-quadraphonic b/etc/speakers-quadraphonic new file mode 100644 index 0000000..9f3f919 --- /dev/null +++ b/etc/speakers-quadraphonic @@ -0,0 +1,8 @@ +0: 1 -0.70710678 0 0.70710678 +1: 1 0.70710678 0 0.70710678 +2: 1 -0.70710678 0 -0.70710678 +3: 1 0.70710678 0 -0.70710678 +4: 0 0 0 0 +5: 0 0 0 0 +6: 0 0 0 0 +7: 0 0 0 0 diff --git a/etc/speakers-sevenpoint-a b/etc/speakers-sevenpoint-a new file mode 100644 index 0000000..d9847f9 --- /dev/null +++ b/etc/speakers-sevenpoint-a @@ -0,0 +1,8 @@ +0: 1 -0.5 0 0.8860254 +1: 1 0.5 0 0.8860254 +2: 1 -0.5 0 -0.8860254 +3: 1 0.5 0 -0.8860254 +4: 1 0 0 1 +5: 0 0 0 0 +6: 1 -1 0 0 +7: 1 1 0 0 diff --git a/etc/speakers-sevenpoint-b b/etc/speakers-sevenpoint-b new file mode 100644 index 0000000..8e3cea8 --- /dev/null +++ b/etc/speakers-sevenpoint-b @@ -0,0 +1,8 @@ +0: 1 -0.78183148 0 0.6234898 +1: 1 0.78183148 0 0.6234898 +2: 1 -0.43388374 0 -0.90096777 +3: 1 0.43388374 0 -0.90096777 +4: 1 0 0 1 +5: 0 0 0 0 +6: 1 0.97492791 0 -0.22252093 +7: 1 -0.97492791 0 -0.22252093 diff --git a/etc/speakers-sevenpoint-c b/etc/speakers-sevenpoint-c new file mode 100644 index 0000000..1eb70c3 --- /dev/null +++ b/etc/speakers-sevenpoint-c @@ -0,0 +1,8 @@ +0: 1 -0.70710678 0 0.70710678 +1: 1 0.70710678 0 0.70710678 +2: 1 -0.70710678 0 -0.70710678 +3: 1 0.70710678 0 -0.70710678 +4: 1 0 0 1 +5: 0 0 0 0 +6: 1 -1 0 0 +7: 1 1 0 0 diff --git a/etc/speakers-stereo b/etc/speakers-stereo new file mode 100644 index 0000000..603c617 --- /dev/null +++ b/etc/speakers-stereo @@ -0,0 +1,8 @@ +0: 1 -1 0 0 +1: 1 1 0 0 +2: 0 0 0 0 +3: 0 0 0 0 +4: 0 0 0 0 +5: 0 0 0 0 +6: 0 0 0 0 +7: 0 0 0 0 diff --git a/include/AL/al.h b/include/AL/al.h new file mode 100644 index 0000000..a747204 --- /dev/null +++ b/include/AL/al.h @@ -0,0 +1,642 @@ +#ifndef __al_h_ +#define __al_h_ + +/** + * 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 "altypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +#ifdef _OPENAL32LIB +#define ALAPI __declspec(dllexport) +#else +#define ALAPI __declspec(dllimport) +#endif +#define ALAPIENTRY __cdecl +#define AL_CALLBACK +#else /* _WIN32 */ + +#ifdef TARGET_OS_MAC +#if TARGET_OS_MAC +#pragma export on +#endif /* TARGET_OS_MAC */ +#endif /* TARGET_OS_MAC */ + +#ifndef ALAPI +#define ALAPI +#endif + +#ifndef ALAPIENTRY +#define ALAPIENTRY +#endif + +#ifndef CALLBACK +#define AL_CALLBACK +#endif + +#endif /* _WIN32 */ + +#define OPENAL + +#ifndef AL_NO_PROTOTYPES + +/** + * OpenAL Maintenance Functions + * State Management and Query. + * Error Handling. + * Extension Support. + */ + + +/** Renderer State management. */ +ALAPI void ALAPIENTRY alEnable( ALenum capability ); + +ALAPI void ALAPIENTRY alDisable( ALenum capability ); + +ALAPI ALboolean ALAPIENTRY alIsEnabled( ALenum capability ); + +/** Application preferences for driver performance choices. */ +ALAPI void ALAPIENTRY alHint( ALenum target, ALenum mode ); + +/** State retrieval. */ +ALAPI void ALAPIENTRY alGetBooleanv( ALenum param, ALboolean* data ); + +/** State retrieval. */ +ALAPI void ALAPIENTRY alGetIntegerv( ALenum param, ALint* data ); + +/** State retrieval. */ +ALAPI void ALAPIENTRY alGetFloatv( ALenum param, ALfloat* data ); + +/** State retrieval. */ +ALAPI void ALAPIENTRY alGetDoublev( ALenum param, ALdouble* data ); + +/** State retrieval. */ +#ifdef LINUX_AL +ALAPI const ALubyte* ALAPIENTRY alGetString( ALenum param ); +#else +ALAPI ALubyte* ALAPIENTRY alGetString( ALenum param ); +#endif + + +/** State retrieval.through return value ( for compatibility ) */ +ALAPI ALboolean ALAPIENTRY alGetBoolean( ALenum param ); +ALAPI ALint ALAPIENTRY alGetInteger( ALenum param ); +ALAPI ALfloat ALAPIENTRY alGetFloat( ALenum param ); +ALAPI ALdouble ALAPIENTRY alGetDouble( ALenum param ); + +/** + * Error support. + * Obtain the most recent error generated in the AL state machine. + */ +ALAPI ALenum ALAPIENTRY alGetError( ALvoid ); + +/** + * Extension support. + * Obtain the address of a function (usually an extension) + * with the name fname. All addresses are context-independent. + */ +#ifdef LINUX_AL +ALAPI ALboolean ALAPIENTRY alIsExtensionPresent( const ALubyte* fname ); +#else +ALAPI ALboolean ALAPIENTRY alIsExtensionPresent( ALubyte* fname ); +#endif + + +/** + * Extension support. + * Obtain the address of a function (usually an extension) + * with the name fname. All addresses are context-independent. + */ +#ifdef LINUX_AL +ALAPI void* ALAPIENTRY alGetProcAddress( const ALubyte* fname ); +#else +ALAPI void* ALAPIENTRY alGetProcAddress( ALubyte* fname ); +#endif + + +/** + * Extension support. + * Obtain the integer value of an enumeration (usually an extension) with the name ename. + */ +#ifdef LINUX_AL +ALAPI ALenum ALAPIENTRY alGetEnumValue( const ALubyte* ename ); +#else +ALAPI ALenum ALAPIENTRY alGetEnumValue( ALubyte* ename ); +#endif + + + + + +/** + * LISTENER + * Listener is the sample position for a given context. + * The multi-channel (usually stereo) output stream generated + * by the mixer is parametrized by this Listener object: + * its position and velocity relative to Sources, within + * occluder and reflector geometry. + */ + + + +/** + * + * Listener Gain: default 1.0f. + */ +ALAPI void ALAPIENTRY alListenerf( ALenum pname, ALfloat param ); + +ALAPI void ALAPIENTRY alListeneri( ALenum pname, ALint param ); + +/** + * + * Listener Position: ALfloat[3] + * Listener Velocity: ALfloat[3] + */ +ALAPI void ALAPIENTRY alListener3f( ALenum pname, + ALfloat f1, ALfloat f2, ALfloat f3 ); + +/** + * + * Listener Position: ALfloat[3] + * Listener Velocity: ALfloat[3] + * Listener Orientation: ALfloat[6] (forward and up vector). + */ +ALAPI void ALAPIENTRY alListenerfv( ALenum pname, ALfloat* param ); + +/* + * Retrieve listener information. + */ +ALAPI void ALAPIENTRY alGetListeneri( ALenum pname, ALint* value ); +ALAPI void ALAPIENTRY alGetListenerf( ALenum pname, ALfloat* value ); +#ifdef LINUX_AL +/* not defined under Windows and MacOS */ +ALAPI void ALAPIENTRY alGetListeneriv( ALenum pname, ALint* value ); +#endif +ALAPI void ALAPIENTRY alGetListenerfv( ALenum pname, ALfloat* values ); + +ALAPI void ALAPIENTRY alGetListener3f( ALenum pname, + ALfloat *f1, ALfloat *f2, ALfloat *f3 ); + +/** + * SOURCE + * Source objects are by default localized. 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. + */ + + + +/** Create Source objects. */ +ALAPI void ALAPIENTRY alGenSources( ALsizei n, ALuint* sources ); + +/** Delete Source objects. */ +ALAPI void ALAPIENTRY alDeleteSources( ALsizei n, ALuint* sources ); + +/** Verify a handle is a valid Source. */ +ALAPI ALboolean ALAPIENTRY alIsSource( ALuint sid ); + + +/** Set an integer parameter for a Source object. */ +ALAPI void ALAPIENTRY alSourcei( ALuint sid, ALenum param, ALint value ); +ALAPI void ALAPIENTRY alSourcef( ALuint sid, ALenum param, ALfloat value ); +ALAPI void ALAPIENTRY alSource3f( ALuint sid, ALenum param, + ALfloat f1, ALfloat f2, ALfloat f3 ); +ALAPI void ALAPIENTRY alSourcefv( ALuint sid, ALenum param, ALfloat* values ); + +/** Get an integer parameter for a Source object. */ +ALAPI void ALAPIENTRY alGetSourcei( ALuint sid, ALenum pname, ALint* value ); +#ifdef LINUX_AL +/* not defined under Windows and MacOS */ +ALAPI void ALAPIENTRY alGetSourceiv( ALuint sid, ALenum pname, ALint* values ); +#endif +ALAPI void ALAPIENTRY alGetSourcef( ALuint sid, ALenum pname, ALfloat* value ); +ALAPI void ALAPIENTRY alGetSourcefv( ALuint sid, ALenum pname, ALfloat* values ); + +/* deprecated, included for Win compatibility */ +ALAPI void ALAPIENTRY alGetSource3f( ALuint sid, ALenum pname, ALfloat* value1, + ALfloat* value2, ALfloat* value3); + +ALAPI void ALAPIENTRY alSourcePlayv( ALsizei ns, ALuint *ids ); +ALAPI void ALAPIENTRY alSourceStopv( ALsizei ns, ALuint *ids ); +ALAPI void ALAPIENTRY alSourceRewindv( ALsizei ns, ALuint *ids ); +ALAPI void ALAPIENTRY alSourcePausev( ALsizei ns, ALuint *ids ); + +/** Activate a source, start replay. */ +ALAPI void ALAPIENTRY alSourcePlay( ALuint sid ); + +/** + * Pause a source, + * temporarily remove it from the mixer list. + */ +ALAPI void ALAPIENTRY alSourcePause( ALuint sid ); + +/** + * Rewind a source, + * set the source to play at the beginning. + */ +ALAPI void ALAPIENTRY alSourceRewind( ALuint sid ); + +/** + * Stop a source, + * temporarily remove it from the mixer list, + * and reset its internal state to pre-Play. + * To remove a Source completely, it has to be + * deleted following Stop, or before Play. + */ +ALAPI void ALAPIENTRY alSourceStop( ALuint sid ); + +/** + * BUFFER + * Buffer objects are storage space for sample data. + * Buffers are referred to by Sources. There can be more than + * one Source using the same Buffer data. If Buffers have + * to be duplicated on a per-Source basis, the driver has to + * take care of allocation, copying, and deallocation as well + * as propagating buffer data changes. + */ + + + + +/** Buffer object generation. */ +ALAPI void ALAPIENTRY alGenBuffers( ALsizei n, ALuint* buffers ); + +ALAPI void ALAPIENTRY alDeleteBuffers( ALsizei n, ALuint* buffers ); + + +ALAPI ALboolean ALAPIENTRY alIsBuffer( ALuint buffer ); + +/** + * Specify the data to be filled into a buffer. + */ +ALAPI void ALAPIENTRY alBufferData( ALuint buffer, + ALenum format, + ALvoid* data, + ALsizei size, + ALsizei freq ); + +ALAPI void ALAPIENTRY alGetBufferi( ALuint buffer, ALenum param, ALint* value ); +ALAPI void ALAPIENTRY alGetBufferf( ALuint buffer, ALenum param, ALfloat* value ); +#ifdef LINUX_AL +/* not defined under Windows and MacOS */ +ALAPI void ALAPIENTRY alGetBufferiv( ALuint buffer, ALenum param, ALint *v); +ALAPI void ALAPIENTRY alGetBufferfv( ALuint buffer, ALenum param, ALfloat *v); +#endif + + + +/** + * Frequency Domain Filters are band filters. + * Attenuation in Media (distance based) + * Reflection Material + * Occlusion Material (separating surface) + * + * Temporal Domain Filters: + * Early Reflections + * Late Reverb + * + */ + + +#ifdef LINUX_AL +/* IASIG stuff never really used -- will probably be removed from Linux as well */ +/** + * EXTENSION: IASIG Level 2 Environment. + * Environment object generation. + * This is an EXTension that describes the Environment/Reverb + * properties according to IASIG Level 2 specifications. + */ + +/** + * Allocate n environment ids and store them in the array environs. + * Returns the number of environments actually allocated. + */ +ALAPI ALsizei ALAPIENTRY alGenEnvironmentIASIG( ALsizei n, ALuint* environs ); + +ALAPI void ALAPIENTRY alDeleteEnvironmentIASIG( ALsizei n, ALuint* environs ); + +ALAPI ALboolean ALAPIENTRY alIsEnvironmentIASIG( ALuint environ ); + +ALAPI void ALAPIENTRY alEnvironmentiIASIG( ALuint eid, ALenum param, ALint value ); + +ALAPI void ALAPIENTRY alEnvironmentfIASIG( ALuint eid, ALenum param, ALuint value ); + +#endif + +/** + * Queue stuff + */ +ALAPI void ALAPIENTRY alSourceQueueBuffers( ALuint sid, ALsizei numEntries, ALuint *bids ); +ALAPI void ALAPIENTRY alSourceUnqueueBuffers( ALuint sid, ALsizei numEntries, ALuint *bids ); + +#ifdef LINUX_AL +/* function no longer used */ +ALAPI void ALAPIENTRY alQueuei( ALuint sid, ALenum param, ALint value ); +#endif + +/** + * Knobs and dials + */ +ALAPI void ALAPIENTRY alDopplerFactor( ALfloat value ); +ALAPI void ALAPIENTRY alDopplerVelocity( ALfloat value ); +ALAPI void ALAPIENTRY alDistanceModel( ALenum distanceModel ); + +#else /* AL_NO_PROTOTYPES */ + + +/** OpenAL Maintenance Functions */ + + void (*alEnable)( ALenum capability ); + void (*alDisable)( ALenum capability ); + ALboolean (*alIsEnabled)( ALenum capability ); + void (*alHint)( ALenum target, ALenum mode ); + ALboolean (*alGetBoolean)( ALenum param ); + ALint (*alGetInteger)( ALenum param ); + ALfloat (*alGetFloat)( ALenum param ); + ALdouble (*alGetDouble)( ALenum param ); + void (*alGetBooleanv)( ALenum param, + ALboolean* data ); + void (*alGetIntegerv)( ALenum param, + ALint* data ); + void (*alGetFloatv)( ALenum param, + ALfloat* data ); + void (*alGetDoublev)( ALenum param, + ALdouble* data ); +#ifdef LINUX_AL + const ALubyte* (*alGetString)( ALenum param ); +#else + ALubyte* (*alGetString)( ALenum param ); +#endif + ALenum (*alGetError)( ALvoid ); + + /** + * Extension support. + * Query existance of extension + */ +#ifdef LINUX_AL + ALboolean (*alIsExtensionPresent)(const ALubyte* fname ); +#else + ALboolean (*alIsExtensionPresent)(ALubyte* fname ); +#endif + + /** + * Extension support. + * Obtain the address of a function (usually an extension) + * with the name fname. All addresses are context-independent. + */ +#ifdef LINUX_AL + void* (*alGetProcAddress)( const ALubyte* fname ); +#else + void* (*alGetProcAddress)( ALubyte* fname ); +#endif + + /** + * Extension support. + * Obtain the integer value of an enumeration (usually an extension) with the name ename. + */ +#ifdef LINUX_AL + ALenum (*alGetEnumValue)( const ALubyte* ename ); +#else + ALenum (*alGetEnumValue)( ALubyte* ename); +#endif + +/** + * LISTENER + * Listener is the sample position for a given context. + * The multi-channel (usually stereo) output stream generated + * by the mixer is parametrized by this Listener object: + * its position and velocity relative to Sources, within + * occluder and reflector geometry. + */ + /** + * + * Listener Gain: default 1.0f. + */ + void (*alListenerf)( ALenum pname, ALfloat param ); + + /** + * + * Listener Position: ALfloat[3] + * Listener Velocity: ALfloat[3] + * Listener Orientation: ALfloat[6] (forward and up vector). + */ + void (*alListenerfv)( ALenum pname, ALfloat* param ); + + /* + * Retrieve listener information. + */ + void (*alGetListeneri)( ALenum pname, ALint* value ); + void (*alGetListenerf)( ALenum pname, ALfloat* value ); + +#ifdef LINUX_AL + void (*alGetListeneriv)( ALenum pname, ALint* values ); +#endif + void (*alGetListenerfv)( ALenum pname, ALfloat* values ); + +/** + * SOURCE + * Source objects are by default localized. 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. + */ + + /** Create Source objects. */ + void (*alGenSources)( ALsizei n, ALuint* sources ); + + /** Delete Source objects. */ + void (*alDeleteSources)( ALsizei n, ALuint* sources ); + + /** Verify a handle is a valid Source. */ + ALboolean (*alIsSource)( ALuint sid ); + + /** Set an integer parameter for a Source object. */ + void (*alSourcei)( ALuint sid, ALenum param, ALint value); + + /** Set a float parameter for a Source object. */ + void (*alSourcef)( ALuint sid, ALenum param, ALfloat value); + + /** Set a 3 float parameter for a Source object. */ + void (*alSource3f)( ALuint sid, ALenum param, + ALfloat f1, ALfloat f2, ALfloat f3 ); + + /** Set a float vector parameter for a Source object. */ + void (*alSourcefv)( ALuint sid, ALenum param, + ALfloat* values ); + + /** Get an integer scalar parameter for a Source object. */ + void (*alGetSourcei)( ALuint sid, + ALenum pname, ALint* value ); + +#ifdef LINUX_AL + /** Get an integer parameter for a Source object. */ + void (*alGetSourceiv)( ALuint sid, + ALenum pname, ALint* values ); +#endif + /** Get a float scalar parameter for a Source object. */ + void (*alGetSourcef)( ALuint sid, + ALenum pname, ALfloat* value ); + + /** Get three float scalar parameter for a Source object. */ + void (*alGetSource3f)( ALuint sid, ALenum pname, + ALfloat* value1, + ALfloat* value2, + ALfloat* value3); + + /** Get a float vector parameter for a Source object. */ + void (*alGetSourcefv)( ALuint sid, + ALenum pname, ALfloat* values ); + + + /** Activate a source, start replay. */ + void (*alSourcePlay)( ALuint sid ); + + /** + * Pause a source, + * temporarily remove it from the mixer list. + */ + void (*alSourcePause)( ALuint sid ); + + /** + * Stop a source, + * temporarily remove it from the mixer list, + * and reset its internal state to pre-Play. + * To remove a Source completely, it has to be + * deleted following Stop, or before Play. + */ + void (*alSourceStop)( ALuint sid ); + + /** + * Rewind a souce. Stopped paused and playing sources, + * resets the offset into the PCM data and sets state to + * AL_INITIAL. + */ + void (*alSourceRewind)( ALuint sid ); + + /** + * vector forms of those functions we all love + */ + void (*alSourcePlayv)( ALsizei ns, ALuint *ids ); + void (*alSourceStopv)( ALsizei ns, ALuint *ids ); + void (*alSourceRewindv)( ALsizei ns, ALuint *ids ); + void (*alSourcePausev)( ALsizei ns, ALuint *ids ); + +/** + * BUFFER + * Buffer objects are storage space for sample data. + * Buffers are referred to by Sources. There can be more than + * one Source using the same Buffer data. If Buffers have + * to be duplicated on a per-Source basis, the driver has to + * take care of allocation, copying, and deallocation as well + * as propagating buffer data changes. + */ + + /** Buffer object generation. */ + void (*alGenBuffers)( ALsizei n, ALuint* buffers ); + void (*alDeleteBuffers)( ALsizei n, ALuint* buffers ); + ALboolean (*alIsBuffer)( ALuint buffer ); + + /** + * Specify the data to be filled into a buffer. + */ + void (*alBufferData)( ALuint buffer, + ALenum format, + ALvoid* data, + ALsizei size, + ALsizei freq ); + + void (*alGetBufferi)( ALuint buffer, + ALenum param, ALint* value ); + void (*alGetBufferf)( ALuint buffer, + ALenum param, ALfloat* value ); +#ifdef LINUX_AL + void (*alGetBufferiv)( ALuint buffer, + ALenum param, ALint* value ); + void (*alGetBufferfv)( ALuint buffer, + ALenum param, ALfloat* value ); +#endif + +#ifdef LINUX_AL +/** + * EXTENSION: IASIG Level 2 Environment. + * Environment object generation. + * This is an EXTension that describes the Environment/Reverb + * properties according to IASIG Level 2 specifications. + */ + /** + * Allocate n environment ids and store them in the array environs. + * Returns the number of environments actually allocated. + */ + ALsizei (*alGenEnvironmentIASIG)( ALsizei n, ALuint* environs ); + void (*alDeleteEnvironmentIASIG)(ALsizei n, + ALuint* environs); + ALboolean (*alIsEnvironmentIASIG)( ALuint environ ); + void (*alEnvironmentiIASIG)( ALuint eid, + ALenum param, ALint value ); + void (*alEnvironmentfIASIG)( ALuint eid, + ALenum param, ALuint value ); + +#endif + + /** + * Queue stuff + */ +#ifdef LINUX_AL + void (*alQueuei)(ALuint sid, ALenum param, ALint value ); +#endif + void (*alSourceUnqueueBuffers)(ALuint sid, ALsizei numEntries, ALuint *bids ); + void (*alSourceQueueBuffers)(ALuint sid, ALsizei numEntries, ALuint *bids ); + + void (*alDopplerFactor)( ALfloat value ); + void (*alDopplerVelocity)( ALfloat value ); + void (*alDistanceModel)( ALenum distanceModel ); + +/** + * Frequency Domain Filters are band filters. + * Attenuation in Media (distance based) + * Reflection Material + * Occlusion Material (separating surface) + * + * Temporal Domain Filters: + * Early Reflections + * Late Reverb + * + */ + +#endif /* AL_NO_PROTOTYPES */ + +#ifdef TARGET_OS_MAC +#if TARGET_OS_MAC +#pragma export off +#endif /* TARGET_OS_MAC */ +#endif /* TARGET_OS_MAC */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __al_h_ */ diff --git a/include/AL/alc.h b/include/AL/alc.h new file mode 100644 index 0000000..ea3e244 --- /dev/null +++ b/include/AL/alc.h @@ -0,0 +1,163 @@ +#ifndef ALC_CONTEXT_H_ +#define ALC_CONTEXT_H_ + +#include "altypes.h" +#include "alctypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ALC_VERSION_0_1 1 + +#ifdef _WIN32 + #ifdef _OPENAL32LIB + #define ALCAPI __declspec(dllexport) + #else + #define ALCAPI __declspec(dllimport) + #endif + + typedef struct ALCdevice_struct ALCdevice; + typedef struct ALCcontext_struct ALCcontext; + + #define ALCAPIENTRY __cdecl +#else + #ifdef TARGET_OS_MAC + #if TARGET_OS_MAC + #pragma export on + #endif + #endif + + #define ALCAPI + #define ALCAPIENTRY +#endif + +#ifndef AL_NO_PROTOTYPES + +ALCAPI ALCcontext * ALCAPIENTRY alcCreateContext( ALCdevice *dev, + ALCint* attrlist ); + +/** + * There is no current context, as we can mix + * several active contexts. But al* calls + * only affect the current context. + */ +#ifdef LINUX_AL +/* spec has return value as ALCboolean */ +ALCAPI ALCenum ALCAPIENTRY alcMakeContextCurrent( ALCcontext *alcHandle ); +#else +ALCAPI ALCboolean ALCAPIENTRY alcMakeContextCurrent(ALCcontext *alcHandle); +#endif + +/** + * Perform processing on a synced context, non-op on a asynchronous + * context. + */ + +#ifdef LINUX_AL +/* spec has return value as void */ +ALCAPI ALCcontext * ALCAPIENTRY alcProcessContext( ALCcontext *alcHandle ); +#else +ALCAPI ALvoid ALCAPIENTRY alcProcessContext(ALCcontext* context); +#endif + +/** + * Suspend processing on an asynchronous context, non-op on a + * synced context. + */ +ALCAPI void ALCAPIENTRY alcSuspendContext( ALCcontext *alcHandle ); + +#ifdef LINUX_AL +/* spec has return value as void */ +ALCAPI ALCenum ALCAPIENTRY alcDestroyContext( ALCcontext *alcHandle ); +#else +ALCAPI ALvoid ALCAPIENTRY alcDestroyContext(ALCcontext* context); +#endif + +ALCAPI ALCenum ALCAPIENTRY alcGetError( ALCdevice *dev ); + +ALCAPI ALCcontext * ALCAPIENTRY alcGetCurrentContext( ALvoid ); + +#ifdef LINUX_AL +ALCAPI ALCdevice * ALCAPIENTRY alcOpenDevice( const ALubyte *tokstr ); +#else +ALCAPI ALCdevice * ALCAPIENTRY alcOpenDevice( ALubyte *tokstr ); +#endif +ALCAPI void ALCAPIENTRY alcCloseDevice( ALCdevice *dev ); + +ALCAPI ALCboolean ALCAPIENTRY alcIsExtensionPresent(ALCdevice *device, ALCubyte *extName); +ALCAPI ALCvoid * ALCAPIENTRY alcGetProcAddress(ALCdevice *device, ALCubyte *funcName); +ALCAPI ALCenum ALCAPIENTRY alcGetEnumValue(ALCdevice *device, ALCubyte *enumName); + +ALCAPI ALCdevice* ALCAPIENTRY alcGetContextsDevice(ALCcontext *context); + + +/** + * Query functions + */ + +#ifdef LINUX_AL +const ALCubyte * ALCAPIENTRY alcGetString( ALCdevice *deviceHandle, ALCenum token ); +#else +ALCAPI ALubyte* ALCAPIENTRY alcGetString(ALCdevice* device, ALenum param); +#endif +#ifdef LINUX_AL +ALCAPI void ALCAPIENTRY alcGetIntegerv( ALCdevice *deviceHandle, ALCenum token , ALCsizei size , ALCint *dest ); +#else +ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALCsizei size,ALCint *data); +#endif + +#else + ALCAPI ALCcontext * ALCAPIENTRY (*alcCreateContext)( ALCdevice *dev, ALCint* attrlist ); +#ifdef LINUX_AL + ALCAPI ALCenum ALCAPIENTRY (*alcMakeContextCurrent)( ALCcontext *alcHandle ); +#else + ALCAPI ALCboolean ALCAPIENTRY (*alcMakeContextCurrent)(ALCcontext *context); +#endif +#ifdef LINUX_AL + ALCAPI ALCcontext * ALCAPIENTRY (*alcProcessContext)( ALCcontext *alcHandle ); +#else + ALCAPI ALCvoid * ALCAPIENTRY (*alcProcessContext)( ALCcontext *alcHandle ); +#endif + ALCAPI void ALCAPIENTRY (*alcSuspendContext)( ALCcontext *alcHandle ); +#ifdef LINUX_AL + ALCAPI ALCenum ALCAPIENTRY (*alcDestroyContext)( ALCcontext *alcHandle ); +#else + ALCAPI ALvoid ALCAPIENTRY (*alcDestroyContext)( ALCcontext* context ); +#endif + ALCAPI ALCenum ALCAPIENTRY (*alcGetError)( ALCdevice *dev ); + ALCAPI ALCcontext * ALCAPIENTRY (*alcGetCurrentContext)( ALCvoid ); +#ifdef LINUX_AL + ALCAPI ALCdevice * ALCAPIENTRY (*alcOpenDevice)( const ALCubyte *tokstr ); +#else + ALCAPI ALCdevice * ALCAPIENTRY (*alcOpenDevice)( ALubyte *tokstr ); +#endif + ALCAPI void ALCAPIENTRY (*alcCloseDevice)( ALCdevice *dev ); + ALCAPI ALCboolean ALCAPIENTRY (*alcIsExtensionPresent)( ALCdevice *device, ALCubyte *extName ); + ALCAPI ALCvoid * ALCAPIENTRY (*alcGetProcAddress)(ALCdevice *device, ALCubyte *funcName ); + ALCAPI ALCenum ALCAPIENTRY (*alcGetEnumValue)(ALCdevice *device, ALCubyte *enumName); + ALCAPI ALCdevice* ALCAPIENTRY (*alcGetContextsDevice)(ALCcontext *context); +#ifdef LINUX_AL + ALCAPI const ALCubyte* ALCAPIENTRY (*alcGetString)( ALCdevice *deviceHandle, ALCenum token ); +#else + ALCAPI ALCubyte* ALCAPIENTRY (*alcGetString)( ALCdevice *deviceHandle, ALCenum token ); +#endif +#ifdef LINUX_AL + ALCAPI void ALCAPIENTRY (*alcGetIntegerv*)( ALCdevice *deviceHandle, ALCenum token , ALCsizei size , ALCint *dest ); +#else + ALCAPI ALCvoid ALCAPIENTRY (*alcGetIntegerv*)( ALCdevice *deviceHandle, ALCenum token , ALCsizei size , ALCint *dest ); +#endif + +#endif /* AL_NO_PROTOTYPES */ + +#ifdef TARGET_OS_MAC +#if TARGET_OS_MAC +#pragma export off +#endif /* TARGET_OS_MAC */ +#endif /* TARGET_OS_MAC */ + +#ifdef __cplusplus +} +#endif + +#endif /* ALC_CONTEXT_H_ */ diff --git a/include/AL/alctypes.h b/include/AL/alctypes.h new file mode 100644 index 0000000..bd8043d --- /dev/null +++ b/include/AL/alctypes.h @@ -0,0 +1,121 @@ +#ifndef _ALCTYPES_H_ +#define _ALCTYPES_H_ + +#if !defined(_WIN32) +struct _AL_device; +typedef struct _AL_device ALCdevice; + +typedef void ALCcontext; +#endif /* _WIN32 */ + +typedef int ALCenum; + +/** ALC boolean type. */ +typedef char ALCboolean; + +/** ALC 8bit signed byte. */ +typedef char ALCbyte; + +/** ALC 8bit unsigned byte. */ +typedef unsigned char ALCubyte; + +/** ALC 16bit signed short integer type. */ +typedef short ALCshort; + +/** ALC 16bit unsigned short integer type. */ +typedef unsigned short ALCushort; + +/** ALC 32bit unsigned integer type. */ +typedef unsigned ALCuint; + +/** ALC 32bit signed integer type. */ +typedef int ALCint; + +/** ALC 32bit floating point type. */ +typedef float ALCfloat; + +/** ALC 64bit double point type. */ +typedef double ALCdouble; + +/** ALC 32bit type. */ +typedef unsigned int ALCsizei; + +/** ALC void type */ +typedef void ALCvoid; + +/* Enumerant values begin at column 50. No tabs. */ + +/* bad value */ +#define ALC_INVALID 0 + +/* 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 + +/** + * 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 + +#endif /* _ALCTYPES_H */ diff --git a/include/AL/alext.h b/include/AL/alext.h new file mode 100644 index 0000000..f869017 --- /dev/null +++ b/include/AL/alext.h @@ -0,0 +1,76 @@ +#ifndef _LAL_EXT_H_ +#define _LAL_EXT_H_ + +#include "AL/altypes.h" +#include "alexttypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ALAPI +#define ALAPI extern +#endif + +#ifndef ALAPIENTRY +#define ALAPIENTRY +#endif + +/* loki */ + +ALAPI ALfloat alcGetAudioChannel_LOKI(ALuint channel); +ALAPI void alcSetAudioChannel_LOKI(ALuint channel, ALfloat volume); +ALAPI void alBombOnError_LOKI(void); +ALAPI void alBufferi_LOKI(ALuint bid, ALenum param, ALint value); +ALAPI void alBufferDataWithCallback_LOKI(ALuint bid, + int (*Callback)(ALuint, ALuint, ALshort *, ALenum, ALint, ALint)); + +ALAPI void alBufferWriteData_LOKI( ALuint buffer, + ALenum format, + ALvoid* data, + ALsizei size, + ALsizei freq, + ALenum internalFormat ); +ALAPI void ALAPIENTRY alGenStreamingBuffers_LOKI( ALsizei n, ALuint *samples ); +ALAPI ALsizei alBufferAppendData_LOKI( ALuint buffer, + ALenum format, + ALvoid* data, + ALsizei size, + ALsizei freq ); + +ALAPI ALsizei alBufferAppendWriteData_LOKI( ALuint buffer, + ALenum format, + ALvoid* data, + ALsizei size, + ALsizei freq, + ALenum internalFormat ); + +/* Capture api */ + +ALAPI ALboolean alCaptureInit_EXT( ALenum format, ALuint rate, ALsizei bufferSize ); +ALAPI ALboolean alCaptureDestroy_EXT( ALvoid ); +ALAPI ALboolean alCaptureStart_EXT( ALvoid ); +ALAPI ALboolean alCaptureStop_EXT( ALvoid ); + +/* Non-blocking device read */ +ALAPI ALsizei alCaptureGetData_EXT( ALvoid* data, ALsizei n, ALenum format, ALuint rate ); + +/* custom loaders */ +ALAPI ALboolean alutLoadVorbis_LOKI(ALuint bid, ALvoid *data, ALint size); +ALAPI ALboolean ALAPIENTRY alutLoadRAW_ADPCMData_LOKI(ALuint bid, ALvoid *data, + ALuint size, ALuint freq, + ALenum format); + +ALAPI ALboolean ALAPIENTRY alutLoadIMA_ADPCMData_LOKI(ALuint bid, ALvoid *data, + ALuint size, + alIMAADPCM_state_LOKI *ias); +ALAPI ALboolean ALAPIENTRY alutLoadMS_ADPCMData_LOKI(ALuint bid, + void *data, int size, + alMSADPCM_state_LOKI *mss); + + +#ifdef __cplusplus +} +#endif + +#endif /* _LAL_EXT_H_ */ diff --git a/include/AL/alexttypes.h b/include/AL/alexttypes.h new file mode 100644 index 0000000..fbb0428 --- /dev/null +++ b/include/AL/alexttypes.h @@ -0,0 +1,161 @@ +#ifndef _LAL_EXTTYPES_H_ +#define _LAL_EXTTYPES_H_ + +#define LAL_OPENAL 1 + +/* format base 0x10000 */ +#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000 +#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001 +#define AL_FORMAT_WAVE_EXT 0x10002 +#define AL_FORMAT_VORBIS_EXT 0x10003 + +/* four point formats */ +#define AL_FORMAT_QUAD8_LOKI 0x10004 +#define AL_FORMAT_QUAD16_LOKI 0x10005 + +/** + * token extensions, base 0x20000 + */ +/** + * Indicate the gain (volume amplification) applied, in a + * normalized linear scale. This affects the value retrieved + * by AL_GAIN. + * + * Type: ALfloat. + * Range: ]0.0- ] + * A value of 1.0 means un-attenuated/unchanged. + * A value of 0.0 is interpreted as zero volume - the channel + * is effectively disabled. + */ +#define AL_GAIN_LINEAR_LOKI 0x20000 + + +/* + * types for special loaders. This should be deprecated in favor + * of the special format tags. + */ + +typedef struct WaveFMT { + ALushort encoding; + ALushort channels; /* 1 = mono, 2 = stereo */ + ALuint frequency; /* One of 11025, 22050, or 44100 Hz */ + ALuint byterate; /* Average bytes per second */ + ALushort blockalign; /* Bytes per sample block */ + ALushort bitspersample; +} alWaveFMT_LOKI; + +typedef struct _MS_ADPCM_decodestate { + ALubyte hPredictor; + ALushort iDelta; + ALshort iSamp1; + ALshort iSamp2; +} alMSADPCM_decodestate_LOKI; + +typedef struct MS_ADPCM_decoder { + alWaveFMT_LOKI wavefmt; + ALushort wSamplesPerBlock; + ALushort wNumCoef; + ALshort aCoeff[7][2]; + /* * * */ + alMSADPCM_decodestate_LOKI state[2]; +} alMSADPCM_state_LOKI; + +typedef struct IMA_ADPCM_decodestate_s { + ALint valprev; /* Previous output value */ + ALbyte index; /* Index into stepsize table */ +} alIMAADPCM_decodestate_LOKI; + +typedef struct IMA_ADPCM_decoder { + alWaveFMT_LOKI wavefmt; + ALushort wSamplesPerBlock; + /* * * */ + alIMAADPCM_decodestate_LOKI state[2]; +} alIMAADPCM_state_LOKI; + +/** + * Context creation extension tokens + * base 0x200000 + */ + +/** + * followed by ### of sources + */ +#define ALC_SOURCES_LOKI 0x200000 + +/** + * followed by ### of buffers + */ +#define ALC_BUFFERS_LOKI 0x200001 + +/* + * Channel operations are probably a big no-no and destined + * for obsolesence. + * + * base 0x300000 + */ +#define ALC_CHAN_MAIN_LOKI 0x300000 +#define ALC_CHAN_PCM_LOKI 0x300001 +#define ALC_CHAN_CD_LOKI 0x300002 + + +typedef void (*PFNALCSETAUDIOCHANNELPROC)(ALuint channel, ALfloat volume); +typedef ALfloat (*PFNALCGETAUDIOCHANNELPROC)(ALuint channel); +typedef void (*PFNALBOMBONERRORPROC)(void); + +typedef void (*PFNALBUFFERIPROC)(ALuint bid, ALenum param, ALint value); + +typedef void (*PFNALBUFFERDATAWITHCALLBACKPROC)(ALuint bid, + int (*Callback)(ALuint, ALuint, ALshort *, ALenum, ALint, ALint)); + +typedef void (*PFNALBUFFERWRITEDATAPROC)( ALuint buffer, + ALenum format, + ALvoid* data, + ALsizei size, + ALsizei freq, + ALenum internalFormat ); + +typedef void (*PFNALGENSTREAMINGBUFFERSPROC)( ALsizei n, ALuint *samples ); + +typedef ALsizei (*PFNALBUFFERAPPENDDATAPROC)( ALuint buffer, + ALenum format, + ALvoid* data, + ALsizei size, + ALsizei freq ); + +typedef ALsizei (*PFNALBUFFERAPPENDWRITEDATAPROC)( ALuint buffer, + ALenum format, + ALvoid* data, + ALsizei size, + ALsizei freq, + ALenum internalFormat ); + +/* captures */ + +typedef ALboolean (*PFNALCAPTUREINITPROC)( ALenum format, ALuint rate, ALsizei bufferSize ); + +typedef ALboolean (*PFNALCAPTUREDESTROYPROC)( ALvoid ); + +typedef ALboolean (*PFNALCAPTURESTARTPROC)( ALvoid ); + +typedef ALboolean (*PFNALCAPTURESTOPPROC)( ALvoid ); + +/* Non-blocking device read */ +typedef ALsizei (*PFNALCAPTUREGETDATAPROC)( ALvoid* data, ALsizei n, ALenum format, ALuint rate ); + +/* vorbis */ +typedef ALboolean (*PFNALUTLOADVORBISPROC)(ALuint bid, ALvoid *data, ALint size); + +/* custom loaders */ +typedef ALboolean (*PFNALUTLOADRAW_ADPCMDATAPROC)( ALuint bid, + ALvoid *data, ALuint size, ALuint freq, + ALenum format); + +typedef ALboolean (*ALUTLOADIMA_ADPCMDATAPROC)(ALuint bid, + ALvoid *data, ALuint size, + alIMAADPCM_state_LOKI *ias); + +typedef ALboolean (*ALUTLOADMS_ADPCMDATAPROC)(ALuint bid, + void *data, int size, + alMSADPCM_state_LOKI *mss); + +#endif /* _LAL_EXTTYPES_H_ */ diff --git a/include/AL/altypes.h b/include/AL/altypes.h new file mode 100644 index 0000000..2ff668f --- /dev/null +++ b/include/AL/altypes.h @@ -0,0 +1,484 @@ +#ifndef _AL_TYPES_H_ +#define _AL_TYPES_H_ + +/* define platform type */ +#if !defined(MACINTOSH_AL) && !defined(LINUX_AL) && !defined(WINDOWS_AL) + #ifdef __APPLE__ + #define MACINTOSH_AL + #else + #ifdef _WIN32 + #define WINDOWS_AL + #else + #define LINUX_AL + #endif + #endif +#endif + +/** OpenAL bool type. */ +typedef char ALboolean; + +/** OpenAL 8bit signed byte. */ +#ifdef LINUX_AL +typedef signed char ALbyte; +#else +typedef char ALbyte; +#endif + +/** OpenAL 8bit unsigned byte. */ +typedef unsigned char ALubyte; + +/** OpenAL 16bit signed short integer type. */ +typedef short ALshort; + +/** OpenAL 16bit unsigned short integer type. */ +typedef unsigned short ALushort; + +/** OpenAL 32bit unsigned integer type. */ +typedef unsigned int ALuint; + +/** OpenAL 32bit signed integer type. */ +typedef int ALint; + +/** OpenAL 32bit floating point type. */ +typedef float ALfloat; + +/** OpenAL 64bit double point type. */ +typedef double ALdouble; + +/** OpenAL 32bit type. */ +/** OpenAL 8bit signed byte. */ +#ifdef LINUX_AL +typedef signed int ALsizei; +#else +typedef unsigned int ALsizei; +#endif + +/** OpenAL void type (for params, not returns). */ +#ifdef LINUX_AL +typedef void ALvoid; +#else +#define ALvoid void +#endif + +/** OpenAL enumerations. */ +typedef int ALenum; + +/** OpenAL bitfields. */ +typedef unsigned int ALbitfield; + +/** OpenAL clamped float. */ +typedef ALfloat ALclampf; + +/** Openal clamped double. */ +typedef ALdouble ALclampd; + +/* Enumerant values begin at column 50. No tabs. */ + +/* bad value */ +#define AL_INVALID -1 + +#define AL_NONE 0 + +/* Boolean False. */ +#define AL_FALSE 0 + +/** Boolean True. */ +#define AL_TRUE 1 + +/** + * Indicate the type of AL_SOURCE. + * Sources can be spatialized + */ +#define AL_SOURCE_TYPE 0x200 + +/** Indicate source has absolute coordinates. */ +#define AL_SOURCE_ABSOLUTE 0x201 + +/** 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, either at source, + * or on mixer results, at listener. + * 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 + +#ifdef LINUX_AL +/* no longer used -- will probably be removed */ +/** + * Indicate whether source is meant to be streaming. + * Type: ALboolean? + * Range: [AL_TRUE, AL_FALSE] + * Default: FALSE. + */ +#define AL_STREAMING 0x1008 +#endif + +/** + * 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 + +#ifdef LINUX_AL +/* byte offset into source (in canon format). -1 if source + * is not playing. Don't set this, get this. + * + * Type: ALint + * Range: -1 - +inf + */ +#define AL_BYTE_LOKI 0x100C +#endif + +/* + * 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 + +/** + * Specify the channel mask. (Creative) + * Type: ALuint + * Range: [0 - 255] + */ +#define AL_CHANNEL_MASK 0x3000 + + +/** + * 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 + +/** 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 +#define AL_DATA 0x2005 + +/** + * 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_ILLEGAL_ENUM 0xA002 +#define AL_INVALID_ENUM 0xA002 + +/** + * Invalid enum parameter value. + */ +#define AL_INVALID_VALUE 0xA003 + +/** + * Illegal call. + */ +#define AL_ILLEGAL_COMMAND 0xA004 +#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 + +#ifdef LINUX_AL +/* no longer used -- will probably be removed */ +/** + * Distance scaling + */ +#define AL_DISTANCE_SCALE 0xC002 +#endif + +/** + * 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 + + +#ifdef LINUX_AL + +/* all the IASIG stuff was never used -- will probably be removed */ + +/** + * enables + */ + +/* #define AL_SOME_ENABLE 0xE000 */ + +/** IASIG Level 2 Environment. */ + +/** + * Parameter: IASIG ROOM blah + * Type: intgeger + * Range: [-10000, 0] + * Default: -10000 + */ +#define AL_ENV_ROOM_IASIG 0x3001 + +/** + * Parameter: IASIG ROOM_HIGH_FREQUENCY + * Type: integer + * Range: [-10000, 0] + * Default: 0 + */ +#define AL_ENV_ROOM_HIGH_FREQUENCY_IASIG 0x3002 + +/** + * Parameter: IASIG ROOM_ROLLOFF_FACTOR + * Type: float + * Range: [0.0, 10.0] + * Default: 0.0 + */ +#define AL_ENV_ROOM_ROLLOFF_FACTOR_IASIG 0x3003 + +/** + * Parameter: IASIG DECAY_TIME + * Type: float + * Range: [0.1, 20.0] + * Default: 1.0 + */ +#define AL_ENV_DECAY_TIME_IASIG 0x3004 + +/** + * Parameter: IASIG DECAY_HIGH_FREQUENCY_RATIO + * Type: float + * Range: [0.1, 2.0] + * Default: 0.5 + */ +#define AL_ENV_DECAY_HIGH_FREQUENCY_RATIO_IASIG 0x3005 + +/** + * Parameter: IASIG REFLECTIONS + * Type: integer + * Range: [-10000, 1000] + * Default: -10000 + */ +#define AL_ENV_REFLECTIONS_IASIG 0x3006 + +/** + * Parameter: IASIG REFLECTIONS_DELAY + * Type: float + * Range: [0.0, 0.3] + * Default: 0.02 + */ +#define AL_ENV_REFLECTIONS_DELAY_IASIG 0x3006 + +/** + * Parameter: IASIG REVERB + * Type: integer + * Range: [-10000,2000] + * Default: -10000 + */ +#define AL_ENV_REVERB_IASIG 0x3007 + +/** + * Parameter: IASIG REVERB_DELAY + * Type: float + * Range: [0.0, 0.1] + * Default: 0.04 + */ +#define AL_ENV_REVERB_DELAY_IASIG 0x3008 + +/** + * Parameter: IASIG DIFFUSION + * Type: float + * Range: [0.0, 100.0] + * Default: 100.0 + */ +#define AL_ENV_DIFFUSION_IASIG 0x3009 + +/** + * Parameter: IASIG DENSITY + * Type: float + * Range: [0.0, 100.0] + * Default: 100.0 + */ +#define AL_ENV_DENSITY_IASIG 0x300A + + /** + * Parameter: IASIG HIGH_FREQUENCY_REFERENCE + * Type: float + * Range: [20.0, 20000.0] + * Default: 5000.0 + */ +#define AL_ENV_HIGH_FREQUENCY_REFERENCE_IASIG 0x300B + +#endif + +#endif diff --git a/include/AL/alu.h b/include/AL/alu.h new file mode 100644 index 0000000..34f6118 --- /dev/null +++ b/include/AL/alu.h @@ -0,0 +1,61 @@ +#ifndef __alu_h_ +#define __alu_h_ + +#ifdef _WIN32 +#define ALUAPI +#define ALUAPIENTRY __cdecl + +#define BUFFERSIZE 48000 +#define FRACTIONBITS 14 +#define FRACTIONMASK ((1L< +#include +#else +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +ALUAPI ALint ALUAPIENTRY aluF2L(ALfloat value); +ALUAPI ALshort ALUAPIENTRY aluF2S(ALfloat value); +ALUAPI ALvoid ALUAPIENTRY aluCrossproduct(ALfloat *inVector1,ALfloat *inVector2,ALfloat *outVector); +ALUAPI ALfloat ALUAPIENTRY aluDotproduct(ALfloat *inVector1,ALfloat *inVector2); +ALUAPI ALvoid ALUAPIENTRY aluNormalize(ALfloat *inVector); +ALUAPI ALvoid ALUAPIENTRY aluMatrixVector(ALfloat *vector,ALfloat matrix[3][3]); +ALUAPI ALvoid ALUAPIENTRY aluCalculateSourceParameters(ALuint source,ALuint channels,ALfloat *drysend,ALfloat *wetsend,ALfloat *pitch); +ALUAPI ALvoid ALUAPIENTRY aluMixData(ALvoid *context,ALvoid *buffer,ALsizei size,ALenum format); +ALUAPI ALvoid ALUAPIENTRY aluSetReverb(ALvoid *Reverb,ALuint Environment); +ALUAPI ALvoid ALUAPIENTRY aluReverb(ALvoid *Reverb,ALfloat Buffer[][2],ALsizei BufferSize); +#endif + +#ifdef TARGET_OS_MAC +#if TARGET_OS_MAC +#pragma export off +#endif /* TARGET_OS_MAC */ +#endif /* TARGET_OS_MAC */ + +#ifdef __cplusplus +} +#endif + +#endif /* __alu_h_ */ + diff --git a/include/AL/alut.h b/include/AL/alut.h new file mode 100644 index 0000000..a46abd7 --- /dev/null +++ b/include/AL/alut.h @@ -0,0 +1,101 @@ +#ifndef _ALUT_H_ +#define _ALUT_H_ + +/* define platform type */ +#if !defined(MACINTOSH_AL) && !defined(LINUX_AL) && !defined(WINDOWS_AL) + #ifdef __APPLE__ + #define MACINTOSH_AL + #else + #ifdef _WIN32 + #define WINDOWS_AL + #else + #define LINUX_AL + #endif + #endif +#endif + +#include "altypes.h" +#include "aluttypes.h" + +#ifdef _WIN32 +#define ALUTAPI +#define ALUTAPIENTRY __cdecl +#define AL_CALLBACK +#else /* _WIN32 */ + +#ifdef TARGET_OS_MAC +#if TARGET_OS_MAC +#pragma export on +#endif /* TARGET_OS_MAC */ +#endif /* TARGET_OS_MAC */ + +#ifndef ALUTAPI +#define ALUTAPI +#endif + +#ifndef ALUTAPIENTRY +#define ALUTAPIENTRY +#endif + +#ifndef AL_CALLBACK +#define AL_CALLBACK +#endif + +#endif /* _WIN32 */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef AL_NO_PROTOTYPES + +ALUTAPI void ALUTAPIENTRY alutInit(int *argc, char *argv[]); +ALUTAPI void ALUTAPIENTRY alutExit(ALvoid); + +#ifdef LINUX_AL +/* this function is Linux-specific and will probably be removed from this header */ +ALUTAPI ALboolean ALUTAPIENTRY alutLoadWAV( const char *fname, ALvoid **wave, ALsizei *format, ALsizei *size, ALsizei *bits, ALsizei *freq ); +#endif + +#ifndef MACINTOSH_AL +/* Windows and Linux versions have a loop parameter, Macintosh doesn't */ +ALUTAPI void ALUTAPIENTRY alutLoadWAVFile(ALbyte *file, ALenum *format, ALvoid **data, ALsizei *size, ALsizei *freq, ALboolean *loop); +ALUTAPI void ALUTAPIENTRY alutLoadWAVMemory(ALbyte *memory, ALenum *format, ALvoid **data, ALsizei *size, ALsizei *freq, ALboolean *loop); +#else +ALUTAPI void ALUTAPIENTRY alutLoadWAVFile(ALbyte *file, ALenum *format, ALvoid **data, ALsizei *size, ALsizei *freq); +ALUTAPI void ALUTAPIENTRY alutLoadWAVMemory(ALbyte *memory, ALenum *format, ALvoid **data, ALsizei *size, ALsizei *freq); +#endif +ALUTAPI void ALUTAPIENTRY alutUnloadWAV(ALenum format, ALvoid *data, ALsizei size, ALsizei freq); + +#else +ALUTAPI void ALUTAPIENTRY (*alutInit)(int *argc, char *argv[]); +ALUTAPI void ALUTAPIENTRY (*alutExit)(ALvoid); + +#ifdef LINUX_AL +/* this function is Linux-specific and will probably be removed from this header */ +ALUTAPI ALboolean ALUTAPIENTRY (*alutLoadWAV)( const char *fname, ALvoid **wave, ALsizei *format, ALsizei *size, ALsizei *bits, ALsizei *freq ); +#endif + +#ifndef MACINTOSH_AL +ALUTAPI void ALUTAPIENTRY (*alutLoadWAVFile(ALbyte *file,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop); +ALUTAPI void ALUTAPIENTRY (*alutLoadWAVMemory)(ALbyte *memory,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop); +#else +ALUTAPI void ALUTAPIENTRY (*alutLoadWAVFile(ALbyte *file,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq); +ALUTAPI void ALUTAPIENTRY (*alutLoadWAVMemory)(ALbyte *memory,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq); +#endif +ALUTAPI void ALUTAPIENTRY (*alutUnloadWAV)(ALenum format,ALvoid *data,ALsizei size,ALsizei freq); + + +#endif /* AL_NO_PROTOTYPES */ + +#ifdef TARGET_OS_MAC +#if TARGET_OS_MAC +#pragma export off +#endif /* TARGET_OS_MAC */ +#endif /* TARGET_OS_MAC */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/AL/aluttypes.h b/include/AL/aluttypes.h new file mode 100644 index 0000000..4b118d9 --- /dev/null +++ b/include/AL/aluttypes.h @@ -0,0 +1,6 @@ +#ifndef _ALUTTYPES_H_ +#define _ALUTTYPES_H_ + +#define AL_PROVIDES_ALUT 1 + +#endif /* _ALUTTYPES_H_ */ diff --git a/include/AL/alutypes.h b/include/AL/alutypes.h new file mode 100644 index 0000000..82356c6 --- /dev/null +++ b/include/AL/alutypes.h @@ -0,0 +1,5 @@ +#ifndef _ALUTYPES_H_ +#define _ALUTYPES_H_ + + +#endif /* _ALUTYPES_H_ */ diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..524cfbb --- /dev/null +++ b/src/Makefile @@ -0,0 +1,62 @@ +# Copyright (C) 2004 Christopher John Purnell +# cjp@lost.org.uk +# +# 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 + +SONAME = libopenal.so.0 +SUFFIX = 1.2 + +LIB=$(SONAME).$(SUFFIX) +PIC=-fPIC + +CC=gcc +#CFLAGS=-O2 -W -Wall -Wmissing-prototypes -Werror $(PIC) +CFLAGS=-O2 -W -Wall -Wmissing-prototypes $(PIC) +LIBS=-lasound -lpthread -lm +SHARED=-shared -Wl,-soname,$(SONAME) +CPPFLAGS=-I../include + +OFILES= al_listener.o al_source.o al_buffer.o al_play.o al_able.o al_state.o \ + al_doppler.o al_distance.o al_error.o al_ext.o al_vector.o \ + alc_context.o alc_speaker.o alc_device.o alc_state.o alc_error.o \ + alc_ext.o alut_main.o alut_wav.o +CFILES= al_listener.c al_source.c al_buffer.c al_play.c al_able.c al_state.c \ + al_doppler.c al_distance.c al_error.c al_ext.c al_vector.c \ + alc_context.c alc_speaker.c alc_device.c alc_state.c alc_error.c \ + alc_ext.c alut_main.c alut_wav.c + +all: $(LIB) + +$(LIB): $(OFILES) + $(CC) $(SHARED) -o $(LIB) $(OFILES) $(LIBS) + +.c.o: + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< + +distclean: clean + rm -f $(LIB) $(PROGS) .depend + +clean: tidy + rm -f *.o + +tidy: + rm -f *~ *.bak *.orig + +depend: + $(CC) $(CPPFLAGS) -M $(CFILES) > .depend + +ifeq (.depend, $(wildcard .depend)) +include .depend +endif diff --git a/src/al_able.c b/src/al_able.c new file mode 100644 index 0000000..11d0339 --- /dev/null +++ b/src/al_able.c @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include "al_error.h" + +ALvoid alEnable(ALenum cap ATTRIBUTE_UNUSED) +{ + _alSetError(AL_ILLEGAL_ENUM); +} + +ALvoid alDisable(ALenum cap ATTRIBUTE_UNUSED) +{ + _alSetError(AL_ILLEGAL_ENUM); +} + +ALboolean alIsEnabled(ALenum cap ATTRIBUTE_UNUSED) +{ + _alSetError(AL_ILLEGAL_ENUM); + return AL_FALSE; +} diff --git a/src/al_buffer.c b/src/al_buffer.c new file mode 100644 index 0000000..8f80af6 --- /dev/null +++ b/src/al_buffer.c @@ -0,0 +1,462 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include "al_buffer.h" +#include "al_error.h" + +#define HASH_SIZE 0x100 +#define HASH_MASK 0x0FF + +static pthread_mutex_t _al_buffer_mutex = PTHREAD_MUTEX_INITIALIZER; + +static ALuint _al_last_buffer_id = 0; +static AL_buffer *_al_buffers[HASH_SIZE]; + +static AL_buffer *_alFindBuffer(ALuint bid) +{ + AL_buffer *buf; + + for (buf = _al_buffers[bid & HASH_MASK]; buf; buf = buf->next) + { + if (buf->id == bid) + { + return buf; + } + } + + return 0; +} + +AL_buffer *_alLockBuffer(ALuint bid) +{ + AL_buffer *buf; + + pthread_mutex_lock(&_al_buffer_mutex); + + if ((buf = _alFindBuffer(bid))) + { + buf->used++; + } + + pthread_mutex_unlock(&_al_buffer_mutex); + + return buf; +} + +ALvoid _alUnlockBuffer(AL_buffer *buf) +{ + pthread_mutex_lock(&_al_buffer_mutex); + + buf->used--; + + pthread_mutex_unlock(&_al_buffer_mutex); +} + +static AL_buffer *_alGenBuffer(ALvoid) +{ + AL_buffer *buf; + ALuint bid; + + if (!(buf = malloc(sizeof(AL_buffer)))) + { + _alSetError(AL_OUT_OF_MEMORY); + return 0; + } + + buf->used = 0; + buf->data = 0; + buf->size = 0; + buf->freq = 0; + + bid = _al_last_buffer_id; + while (!++bid || _alFindBuffer(bid)); + _al_last_buffer_id = bid; + + buf->id = bid; + + buf->next = _al_buffers[bid & HASH_MASK]; + _al_buffers[bid & HASH_MASK] = buf; + + return buf; +} + +static ALvoid _alDeleteBuffer(AL_buffer *buf) +{ + AL_buffer *b, **p; + + for (p = &_al_buffers[buf->id & HASH_MASK]; (b = *p); p = &b->next) + { + if (b->id == buf->id) + { + *p = b->next; + break; + } + } + + if (buf->data) free(buf->data); + free(buf); +} + +ALvoid alGenBuffers(ALsizei n, ALuint *buffers) +{ + ALsizei i; + AL_buffer **temp; + + if (n == 0) + return; + + if (n < 0) + { + _alSetError(AL_INVALID_VALUE); + return; + } + + temp = alloca(n * sizeof(AL_buffer *)); + + pthread_mutex_lock(&_al_buffer_mutex); + + for (i = 0; i < n; i++) + { + if (!(temp[i] = _alGenBuffer())) + { + ALsizei j; + + for (j = 0; j < i; j++) + { + _alDeleteBuffer(temp[j]); + } + + goto unlock; + } + } + + for (i = 0; i < n; i++) + { + buffers[i] = temp[i]->id; + } + +unlock: + pthread_mutex_unlock(&_al_buffer_mutex); +} + +ALvoid alDeleteBuffers(ALsizei n, ALuint *buffers) +{ + ALsizei i; + AL_buffer **temp; + + if (n == 0) + { + return; + } + + if (n < 0) + { + _alSetError(AL_INVALID_VALUE); + return; + } + + temp = alloca(n * sizeof(AL_buffer *)); + + pthread_mutex_lock(&_al_buffer_mutex); + + for (i = 0; i < n; i++) + { + if (!(temp[i] = _alFindBuffer(buffers[i]))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + + if (temp[i]->used) + { + _alSetError(AL_INVALID_OPERATION); + goto unlock; + } + } + + for (i = 0; i < n; i++) + { + _alDeleteBuffer(temp[i]); + } + +unlock: + pthread_mutex_unlock(&_al_buffer_mutex); +} + +ALboolean alIsBuffer(ALuint bid) +{ + ALboolean value; + + pthread_mutex_lock(&_al_buffer_mutex); + + value = _alFindBuffer(bid) ? AL_TRUE : AL_FALSE; + + pthread_mutex_unlock(&_al_buffer_mutex); + + return value; +} + +static ALvoid _alBufferMono8(AL_buffer *buf, ALvoid *data, + ALsizei size, ALsizei freq) +{ + ALvoid *copy; + ALsizei frames = size; + + if (!(copy = malloc(frames << 2))) + { + _alSetError(AL_OUT_OF_MEMORY); + return; + } + + { + __uint8_t *from = data; + __int16_t *to = copy; + ALsizei i; + + for (i = 0; i < frames; i++) + { + __int16_t value = (*(from++) - 128) << 8; + *(to++) = value; + *(to++) = value; + } + } + + buf->data = copy; + buf->size = frames; + buf->freq = freq; +} + +static ALvoid _alBufferMono16(AL_buffer *buf, ALvoid *data, + ALsizei size, ALsizei freq) +{ + ALvoid *copy; + ALsizei frames = size >> 1; + + if (!(copy = malloc(frames << 2))) + { + _alSetError(AL_OUT_OF_MEMORY); + return; + } + + { + __int16_t *from = data; + __int16_t *to = copy; + ALsizei i; + + for (i = 0; i < frames; i++) + { + __int16_t value = *(from++); + *(to++) = value; + *(to++) = value; + } + } + + buf->data = copy; + buf->size = frames; + buf->freq = freq; +} + +static ALvoid _alBufferStereo8(AL_buffer *buf, ALvoid *data, + ALsizei size, ALsizei freq) +{ + ALvoid *copy; + ALsizei frames = size >> 1; + + if (!(copy = malloc(frames << 2))) + { + _alSetError(AL_OUT_OF_MEMORY); + return; + } + + { + __uint8_t *from = data; + __int16_t *to = copy; + ALsizei i; + + for (i = 0; i < frames; i++) + { + *(to++) = (*(from++) - 128) << 8; + *(to++) = (*(from++) - 128) << 8; + } + } + + buf->data = copy; + buf->size = frames; + buf->freq = freq; +} + +static ALvoid _alBufferStereo16(AL_buffer *buf, ALvoid *data, + ALsizei size, ALsizei freq) +{ + ALvoid *copy; + ALsizei frames = size >> 2; + + if (!(copy = malloc(frames << 2))) + { + _alSetError(AL_OUT_OF_MEMORY); + return; + } + + { + __int32_t *from = data; + __int32_t *to = copy; + ALsizei i; + + for (i = 0; i < frames; i++) + { + *(to++) = *(from++); + } + } + + buf->data = copy; + buf->size = frames; + buf->freq = freq; +} + +ALvoid alBufferData(ALuint bid, ALenum format, ALvoid *data, + ALsizei size, ALsizei freq) +{ + AL_buffer *buf; + + if (!(buf = _alLockBuffer(bid))) + { + _alSetError(AL_INVALID_NAME); + return; + } + + if (buf->used > 1) + { + _alSetError(AL_INVALID_OPERATION); + goto unlock; + } + + if (buf->data) + { + free(buf->data); + buf->data = 0; + buf->size = 0; + } + + switch (format) + { + case AL_FORMAT_MONO8: + _alBufferMono8(buf, data, size, freq); + break; + case AL_FORMAT_MONO16: + _alBufferMono16(buf, data, size, freq); + break; + case AL_FORMAT_STEREO8: + _alBufferStereo8(buf, data, size, freq); + break; + case AL_FORMAT_STEREO16: + _alBufferStereo16(buf, data, size, freq); + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + +unlock: + _alUnlockBuffer(buf); +} + +ALvoid alGetBufferi(ALuint bid, ALenum param, ALint *value) +{ + AL_buffer *buf; + + pthread_mutex_lock(&_al_buffer_mutex); + + if (!(buf = _alFindBuffer(bid))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + + switch (param) + { + case AL_FREQUENCY: + *value = (ALint)buf->freq; + break; + case AL_BITS: + *value = 16; + break; + case AL_CHANNELS: + *value = 2; + break; + case AL_SIZE: + *value = (ALint)(buf->size << 2); + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + +unlock: + pthread_mutex_unlock(&_al_buffer_mutex); +} + +ALvoid alGetBufferf(ALuint bid, ALenum param, ALfloat *value) +{ + AL_buffer *buf; + + pthread_mutex_lock(&_al_buffer_mutex); + + if (!(buf = _alLockBuffer(bid))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + + switch (param) + { + case AL_FREQUENCY: + *value = (ALfloat)buf->freq; + break; + case AL_BITS: + *value = 16.0f; + break; + case AL_CHANNELS: + *value = 2.0f; + break; + case AL_SIZE: + *value = (ALfloat)(buf->size << 2); + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + +unlock: + pthread_mutex_lock(&_al_buffer_mutex); +} + +ALvoid alGetBufferiv(ALuint bid, ALenum param, ALint *values) +{ + alGetBufferi(bid, param, values); +} + +ALvoid alGetBufferfv(ALuint bid, ALenum param, ALfloat *values) +{ + alGetBufferf(bid, param, values); +} diff --git a/src/al_buffer.h b/src/al_buffer.h new file mode 100644 index 0000000..13e7ca2 --- /dev/null +++ b/src/al_buffer.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _AL_BUFFER_H_ +#define _AL_BUFFER_H_ + +#include +#include + +typedef struct _AL_buffer +{ + struct _AL_buffer *next; + ALuint id; + ALuint used; + int32_t *data; + ALuint size; + ALuint freq; +} +AL_buffer; + +AL_buffer *_alLockBuffer(ALuint); +ALvoid _alUnlockBuffer(AL_buffer *); + +#endif diff --git a/src/al_distance.c b/src/al_distance.c new file mode 100644 index 0000000..e7aae4b --- /dev/null +++ b/src/al_distance.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "al_source.h" +#include "al_error.h" +#include "alc_context.h" + +static ALfloat _alDistanceNone(AL_source *src, ALfloat dist ATTRIBUTE_UNUSED) +{ + return src->gain; +} + +ALfloat _alDistanceInverse(AL_source *src, ALfloat dist) +{ + ALfloat ref = src->reference_distance; + + if (dist < ref) + { + dist = ref; + } + + return src->gain * ref / (ref + src->rolloff_factor * (dist - ref)); +} + +static ALfloat _alDistanceInverseClamped(AL_source *src, ALfloat dist) +{ + ALfloat ref = src->reference_distance; + + if (dist < ref) + { + dist = ref; + } + + if (dist > src->max_distance) + { + dist = src->max_distance; + } + + return src->gain * ref / (ref + src->rolloff_factor * (dist - ref)); +} + + +ALvoid alDistanceModel(ALenum model) +{ + AL_context *ctx; + ALfloat (*df)(AL_source *, ALfloat); + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + switch (model) + { + case AL_NONE: + df = _alDistanceNone; + break; + case AL_INVERSE_DISTANCE: + df = _alDistanceInverse; + break; + case AL_INVERSE_DISTANCE_CLAMPED: + df = _alDistanceInverseClamped; + break; + default: + _alSetError(AL_ILLEGAL_ENUM); + goto unlock; + } + + ctx->distance_model = model; + ctx->distance_func = df; + +unlock: + _alcUnlockContext(ctx); +} diff --git a/src/al_doppler.c b/src/al_doppler.c new file mode 100644 index 0000000..72a7c93 --- /dev/null +++ b/src/al_doppler.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "alc_context.h" +#include "al_error.h" + +ALvoid alDopplerFactor(ALfloat value) +{ + AL_context *ctx; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + _alRangedAssign1(ctx->doppler_factor, value, 0.0f); + + _alcUnlockContext(ctx); +} + +ALvoid alDopplerVelocity(ALfloat value) +{ + AL_context *ctx; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + _alRangedAssign1(ctx->doppler_velocity, value, 0.0f); + + _alcUnlockContext(ctx); +} diff --git a/src/al_error.c b/src/al_error.c new file mode 100644 index 0000000..0d1e022 --- /dev/null +++ b/src/al_error.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "al_error.h" + +static ALenum __al_error = AL_NO_ERROR; + +ALenum alGetError(ALvoid) +{ + ALenum err = __al_error; + __al_error = AL_NO_ERROR; + return err; +} + +ALvoid _alSetError(ALenum err) +{ + if (__al_error == AL_NO_ERROR) + { + __al_error = err; + } +} diff --git a/src/al_error.h b/src/al_error.h new file mode 100644 index 0000000..84d645d --- /dev/null +++ b/src/al_error.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _AL_ERROR_H_ +#define _AL_ERROR_H_ + +#include + +extern ALvoid _alSetError(ALenum); + +#define _alRangedAssignB(x, v) \ + x = v ? AL_TRUE : AL_FALSE + +#define _alRangedAssign1(x, v, lo) \ + if (v < lo) \ + _alSetError(AL_INVALID_VALUE); \ + else \ + x = (ALfloat)v + +#define _alRangedAssign2(x, v, lo, hi) \ + if (v < lo || v > hi) \ + _alSetError(AL_INVALID_VALUE); \ + else \ + x = (ALfloat)v + +#endif diff --git a/src/al_ext.c b/src/al_ext.c new file mode 100644 index 0000000..6af2bff --- /dev/null +++ b/src/al_ext.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +#include +#include + +static struct { const ALubyte *name; ALenum value; } _al_enums[]= { + { "AL_INVALID", AL_INVALID }, + { "AL_NONE", AL_NONE }, + { "AL_FALSE", AL_FALSE }, + { "AL_TRUE", AL_TRUE }, + + { "ALC_INVALID", ALC_INVALID }, + { "ALC_TRUE", ALC_TRUE }, + { "ALC_FALSE", ALC_FALSE }, + + { "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_SOURCE_STATE", AL_SOURCE_STATE }, + { "AL_INITIAL", AL_INITIAL }, + { "AL_PLAYING", AL_PLAYING }, + { "AL_PAUSED", AL_PAUSED }, + { "AL_STOPPED", AL_STOPPED }, + + { "AL_BUFFERS_QUEUED", AL_BUFFERS_QUEUED }, + { "AL_BUFFERS_PROCESSED", AL_BUFFERS_PROCESSED }, + + { "AL_FORMAT_MONO8", AL_FORMAT_MONO8 }, + { "AL_FORMAT_MONO16", AL_FORMAT_MONO16 }, + { "AL_FORMAT_STEREO8", AL_FORMAT_STEREO8 }, + { "AL_FORMAT_STEREO16", AL_FORMAT_STEREO16 }, + + { "AL_FREQUENCY", AL_FREQUENCY }, + { "AL_BITS", AL_BITS }, + { "AL_CHANNELS", AL_CHANNELS }, + { "AL_SIZE", AL_SIZE }, + { "AL_DATA", AL_DATA }, + + { "AL_UNUSED", AL_UNUSED }, + { "AL_PENDING", AL_PENDING }, + { "AL_PROCESSED", AL_PROCESSED }, + + { "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_EXTENSIONS", ALC_EXTENSIONS }, + { "ALC_FREQUENCY", ALC_FREQUENCY }, + { "ALC_REFRESH", ALC_REFRESH }, + { "ALC_SYNC", ALC_SYNC }, + + { "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 }, + + { "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 }, + + { "AL_VENDOR", AL_VENDOR }, + { "AL_VERSION", AL_VERSION }, + { "AL_RENDERER", AL_RENDERER }, + { "AL_EXTENSIONS", AL_EXTENSIONS }, + + { "AL_DOPPLER_FACTOR", AL_DOPPLER_FACTOR }, + { "AL_DOPPLER_VELOCITY", AL_DOPPLER_VELOCITY }, + { "AL_DISTANCE_MODEL", AL_DISTANCE_MODEL }, + + { "AL_INVERSE_DISTANCE", AL_INVERSE_DISTANCE }, + { "AL_INVERSE_DISTANCE_CLAMPED", AL_INVERSE_DISTANCE_CLAMPED }, + + { 0, 0 } +}; + +ALboolean alIsExtensionPresent(const ALubyte *name ATTRIBUTE_UNUSED) +{ + return AL_FALSE; +} + + +ALvoid *alGetProcAddress(const ALubyte *name ATTRIBUTE_UNUSED) +{ + return 0; +} + + +ALenum alGetEnumValue(const ALubyte *name) +{ + ALuint i=0; + + while ((_al_enums[i].name) && strcmp(_al_enums[i].name, name)) + { + i++; + } + + return _al_enums[i].value; +} diff --git a/src/al_listener.c b/src/al_listener.c new file mode 100644 index 0000000..455424f --- /dev/null +++ b/src/al_listener.c @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "al_listener.h" +#include "al_error.h" +#include "al_vector.h" +#include "alc_context.h" + +static ALvoid _alListenerSetSpeakers(AL_listener *listener, + AL_speaker *speakers) +{ + ALfloat matrix[9]; + ALuint i; + + _alVectorCrossProduct(matrix + 0, listener->orientation, + listener->orientation + 3); + _alVectorNormalize(matrix + 0, matrix + 0); + + _alVectorCrossProduct(matrix + 3, listener->orientation + 0, + matrix + 0); + _alVectorNormalize(matrix + 3, matrix + 3); + + _alVectorNormalize(matrix + 6, listener->orientation + 0); + + for (i = 0; i < _ALC_NUM_SPEAKERS; i++) + { + _alVectorMatrix(listener->speakers[i].position, + speakers[i].position, matrix); + } +} + +ALvoid _alInitListener(AL_listener *listener, AL_speaker *speakers) +{ + ALuint i; + + listener->gain = 1.0f; + + listener->position[0] = 0.0f; + listener->position[1] = 0.0f; + listener->position[2] = 0.0f; + + listener->velocity[0] = 0.0f; + listener->velocity[1] = 0.0f; + listener->velocity[2] = 0.0f; + + listener->orientation[0] = 0.0f; + listener->orientation[1] = 0.0f; + listener->orientation[2] = 0.0f; + listener->orientation[3] = 0.0f; + listener->orientation[4] = 0.0f; + listener->orientation[5] = 0.0f; + + for (i = 0; i < _ALC_NUM_SPEAKERS; i++) + { + listener->speakers[i].gain = speakers[i].gain; + } + + _alListenerSetSpeakers(listener, speakers); +} + +ALvoid alListeneri(ALenum pname, ALint value) +{ + alListenerf(pname, (ALfloat)value); +} + +ALvoid alListenerf(ALenum pname, ALfloat value) +{ + AL_context *ctx; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + switch (pname) + { + case AL_GAIN: + _alRangedAssign1(ctx->listener.gain, value, 0.0f); + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + + _alcUnlockContext(ctx); +} + +ALvoid alListener3f(ALenum pname, ALfloat f1, ALfloat f2, ALfloat f3) +{ + AL_context *ctx; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + switch (pname) + { + case AL_POSITION: + ctx->listener.position[0] = f1; + ctx->listener.position[1] = f2; + ctx->listener.position[2] = f3; + break; + case AL_VELOCITY: + ctx->listener.velocity[0] = f1; + ctx->listener.velocity[1] = f2; + ctx->listener.velocity[2] = f3; + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + + _alcUnlockContext(ctx); +} + +ALvoid alListenerfv(ALenum pname, ALfloat* values) +{ + AL_context *ctx; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + switch (pname) + { + case AL_POSITION: + ctx->listener.position[0] = values[0]; + ctx->listener.position[1] = values[1]; + ctx->listener.position[2] = values[2]; + break; + case AL_VELOCITY: + ctx->listener.velocity[0] = values[0]; + ctx->listener.velocity[1] = values[1]; + ctx->listener.velocity[2] = values[2]; + break; + case AL_GAIN: + _alRangedAssign1(ctx->listener.gain, values[0], 0.0f); + break; + case AL_ORIENTATION: + ctx->listener.orientation[0] = values[0]; + ctx->listener.orientation[1] = values[1]; + ctx->listener.orientation[2] = values[2]; + ctx->listener.orientation[3] = values[3]; + ctx->listener.orientation[4] = values[4]; + ctx->listener.orientation[5] = values[5]; + _alListenerSetSpeakers(&ctx->listener, ctx->speakers); + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + + _alcUnlockContext(ctx); +} + +ALvoid alGetListeneri(ALenum pname, ALint *value) +{ + ALint values[6]; + + values[0] = *value; + alGetListeneriv(pname, values); + *value = values[0]; +} + +ALvoid alGetListeneriv(ALenum pname, ALint* values) +{ + AL_context *ctx; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + switch (pname) + { + case AL_POSITION: + values[0] = (ALint)ctx->listener.position[0]; + values[1] = (ALint)ctx->listener.position[1]; + values[2] = (ALint)ctx->listener.position[2]; + break; + case AL_VELOCITY: + values[0] = (ALint)ctx->listener.velocity[0]; + values[1] = (ALint)ctx->listener.velocity[1]; + values[2] = (ALint)ctx->listener.velocity[2]; + break; + case AL_GAIN: + values[0] = (ALint)ctx->listener.gain; + break; + case AL_ORIENTATION: + values[0] = (ALint)ctx->listener.orientation[0]; + values[1] = (ALint)ctx->listener.orientation[1]; + values[2] = (ALint)ctx->listener.orientation[2]; + values[3] = (ALint)ctx->listener.orientation[3]; + values[4] = (ALint)ctx->listener.orientation[4]; + values[5] = (ALint)ctx->listener.orientation[5]; + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + + _alcUnlockContext(ctx); +} + +ALvoid alGetListenerf(ALenum pname, ALfloat *value) +{ + ALfloat values[6]; + + values[0] = *value; + alGetListenerfv(pname, values); + *value = values[0]; +} + +ALvoid alGetListener3f(ALenum pname, ALfloat *f1, ALfloat *f2, ALfloat *f3) +{ + ALfloat values[6]; + + values[0] = *f1; + values[1] = *f2; + values[2] = *f3; + + alGetListenerfv(pname, values); + + *f1 = values[0]; + *f2 = values[1]; + *f3 = values[2]; +} + +ALvoid alGetListenerfv(ALenum pname, ALfloat* values) +{ + AL_context *ctx; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + switch (pname) + { + case AL_POSITION: + values[0] = ctx->listener.position[0]; + values[1] = ctx->listener.position[1]; + values[2] = ctx->listener.position[2]; + break; + case AL_VELOCITY: + values[0] = ctx->listener.velocity[0]; + values[1] = ctx->listener.velocity[1]; + values[2] = ctx->listener.velocity[2]; + break; + case AL_GAIN: + values[0] = ctx->listener.gain; + break; + case AL_ORIENTATION: + values[0] = ctx->listener.orientation[0]; + values[1] = ctx->listener.orientation[1]; + values[2] = ctx->listener.orientation[2]; + values[3] = ctx->listener.orientation[3]; + values[4] = ctx->listener.orientation[4]; + values[5] = ctx->listener.orientation[5]; + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + + _alcUnlockContext(ctx); +} diff --git a/src/al_listener.h b/src/al_listener.h new file mode 100644 index 0000000..f44aa9c --- /dev/null +++ b/src/al_listener.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _AL_LISTENER_H_ +#define _AL_LISTENER_H_ + +#include + +#include "alc_speaker.h" + +typedef struct _AL_listener { + ALfloat gain; + ALfloat position[3]; + ALfloat velocity[3]; + ALfloat orientation[6]; + AL_speaker speakers[_ALC_NUM_SPEAKERS]; +} AL_listener; + +extern ALvoid _alInitListener(AL_listener *, AL_speaker *); + +#endif diff --git a/src/al_play.c b/src/al_play.c new file mode 100644 index 0000000..20abe1b --- /dev/null +++ b/src/al_play.c @@ -0,0 +1,642 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include "al_source.h" +#include "al_error.h" +#include "al_vector.h" +#include "alc_device.h" +#include "alc_context.h" + +static ALfloat _alCalculateGainAndPitch(AL_source *src) +{ + AL_context *ctx = src->context; + ALCdevice *dev = ctx->device; + ALfloat position[3]; + + position[0] = src->position[0]; + position[1] = src->position[1]; + position[2] = src->position[2]; + + if (!src->relative) + { + position[0] -= ctx->listener.position[0]; + position[1] -= ctx->listener.position[1]; + position[2] -= ctx->listener.position[2]; + } + + /* Master Gain */ + { + ALint volume; + ALfloat gain = ctx->listener.gain; + ALfloat dist = _alVectorMagnitude(position); + + gain *= ctx->distance_func(src, dist); + + if (dist) + { + position[0] /= dist; + position[1] /= dist; + position[2] /= dist; + } + + if (src->conic) + { + ALfloat a; + + a = _alVectorDotProduct(position, src->direction); + + a = acos(-a) * 360.0 / M_PI; + + if (a > src->cone_inner_angle) + { + if (a >= src->cone_outer_angle) + { + gain *= src->cone_outer_gain; + } + else + { + a -= src->cone_inner_angle; + a *= (src->cone_outer_gain - 1.0f); + a /= (src->cone_outer_angle - + src->cone_inner_angle); + gain *= (1.0f + a); + } + } + } + + if (gain > src->max_gain) + { + gain = src->max_gain; + } + else if (gain < src->min_gain) + { + gain = src->min_gain; + } + + volume = (ALint)(65535.0f * gain); + + snd_ctl_elem_value_set_integer(src->vol_ctl, 1, volume); + snd_ctl_elem_value_set_integer(src->vol_ctl, 2, volume); + } + + /* Speaker Gains */ + { + ALuint i; + ALint volume[_ALC_NUM_SPEAKERS]; + + for (i = 0; i < _ALC_NUM_SPEAKERS; i++) + { + AL_speaker *speaker = &ctx->listener.speakers[i]; + + volume[i] = speaker->gain ? + (ALint)((_alVectorDotProduct + (position, speaker->position) + 1.0f) + * speaker->gain) : 0; + } + + if (dev->send_count == 24) + { + snd_ctl_elem_value_set_integer(src->send_ctl, 8, + volume[0]); + snd_ctl_elem_value_set_integer(src->send_ctl, 10, + volume[2]); + + snd_ctl_elem_value_set_integer(src->send_ctl, 12, + (volume[4] + 1) >> 1); + snd_ctl_elem_value_set_integer(src->send_ctl, 13, + (volume[5] + 1) >> 1); + + snd_ctl_elem_value_set_integer(src->send_ctl, 14, + volume[6]); + + snd_ctl_elem_value_set_integer(src->send_ctl, 17, + volume[1]); + snd_ctl_elem_value_set_integer(src->send_ctl, 19, + volume[3]); + + snd_ctl_elem_value_set_integer(src->send_ctl, 20, + volume[4] >> 1); + snd_ctl_elem_value_set_integer(src->send_ctl, 21, + volume[5] >> 1); + + snd_ctl_elem_value_set_integer(src->send_ctl, 23, + volume[7]); + } + else + { + snd_ctl_elem_value_set_integer(src->send_ctl, 4, + volume[0]); + snd_ctl_elem_value_set_integer(src->send_ctl, 5, + volume[2]); + + snd_ctl_elem_value_set_integer(src->send_ctl, 6, + (volume[4] + 1) >> 1); + snd_ctl_elem_value_set_integer(src->send_ctl, 7, + (volume[5] + 1) >> 1); + + snd_ctl_elem_value_set_integer(src->send_ctl, 8, + volume[1]); + snd_ctl_elem_value_set_integer(src->send_ctl, 9, + volume[3]); + + snd_ctl_elem_value_set_integer(src->send_ctl, 10, + volume[4] >> 1); + snd_ctl_elem_value_set_integer(src->send_ctl, 11, + volume[5] >> 1); + } + } + + /* Pitch */ + { + ALfloat vl, vs; + ALfloat pitch = src->pitch; + + if (ctx->doppler_factor) + { + vl = _alVectorDotProduct(ctx->listener.velocity, + position); + vs = _alVectorDotProduct(src->velocity, position); + + vl *= ctx->doppler_factor; + vs *= ctx->doppler_factor; + + vl += ctx->doppler_velocity; + vs += ctx->doppler_velocity; + + pitch *= vl / vs; + } + + if (pitch < 0.0f) + { + pitch = 0.0f; + } + + return pitch; + } +} + +static snd_pcm_uframes_t _alWriteData(AL_source *src, ALfloat pitch, + int32_t *dest, snd_pcm_uframes_t frames) +{ + AL_queue *que; + AL_buffer *buf; + ALfloat f; + ALuint inc, acc; + ALuint i; + + if (!src->playing) + { + return 0; + } + + if ((que = src->current_q) || + ((que = src->first_q) && (que->state == AL_PENDING))) + { + buf = que->buffer; + } + else if ((buf = src->buffer)) + { + que = 0; + } + else + { + src->playing = AL_FALSE; + return 0; + } + + f = pitch * (ALfloat)buf->freq / (ALfloat)src->freq; + inc = (f >= 65535.0) ? 0xFFFF0000 : (ALuint)(f * 65536.0); + acc = 0; + i = 0; + + while (i < frames) + { + ALuint j = src->index; + + if (j >= buf->size) + { + src->index = 0; + + if (que) + { + que->state = AL_PROCESSED; + src->current_q = que->next; + } + else if(!src->looping) + { + src->playing = AL_FALSE; + } + + break; + } + + dest[i++] = buf->data[j]; + acc += inc; + src->index = j + (acc >> 16); + acc &= 0xFFFF; + } + + return i; +} + +ALvoid _alProcessSource(AL_source *src) +{ + const snd_pcm_channel_area_t *area; + snd_pcm_sframes_t avail; + ALfloat pitch; + int state; + + if (src->state != AL_PLAYING) + { + return; + } + + snd_pcm_hwsync(src->handle); + + state = snd_pcm_state(src->handle); + + if (state != SND_PCM_STATE_RUNNING) + { + if (src->playing) + { + snd_pcm_prepare(src->handle); + } + else + { + src->state = AL_STOPPED; + return; + } + } + + pitch = _alCalculateGainAndPitch(src); + + avail = snd_pcm_avail_update(src->handle); + + while (avail > 0) + { + snd_pcm_uframes_t offset; + snd_pcm_uframes_t frames = avail; + snd_pcm_uframes_t written = 0; + int32_t *map; + + if (snd_pcm_mmap_begin(src->handle, &area, &offset, &frames)) + { + return; + } + + avail -= frames; + + map = area->addr + ((area->first + area->step * offset) >> 3); + + while (frames) + { + snd_pcm_uframes_t f; + + if (!(f = _alWriteData(src, pitch, map, frames))) + { + bzero(map, frames << 2); + avail = 0; + break; + } + + map += f; + written += f; + frames -= f; + } + + snd_pcm_mmap_commit(src->handle, offset, written); + } + + { + AL_context *ctx = src->context; + ALCdevice *dev = ctx->device; + + snd_ctl_elem_write(dev->ctl, src->vol_ctl); + snd_ctl_elem_write(dev->ctl, src->send_ctl); + } + + if (state != SND_PCM_STATE_RUNNING) + { + if (!snd_pcm_delay(src->handle, &avail)) + { + if (avail) + { + snd_pcm_start(src->handle); + } + } + } + + if (!src->playing) + { + snd_pcm_drain(src->handle); + } +} + +static ALvoid _alSourcePlay(AL_source *src) +{ + switch(src->state) + { + case AL_PAUSED: + snd_pcm_pause(src->handle, 0); + break; + case AL_PLAYING: + src->index = 0; + break; + } + src->state = AL_PLAYING; + src->playing = AL_TRUE; +} + +static ALvoid _alSourceStop(AL_source *src) +{ + switch (src->state) + { + case AL_PAUSED: + snd_pcm_pause(src->handle, 0); + break; + case AL_PLAYING: + snd_pcm_drop(src->handle); + break; + } + src->state = AL_STOPPED; + src->index = 0; +} + +static ALvoid _alSourcePause(AL_source *src) +{ + if (src->state == AL_PLAYING) + { + snd_pcm_pause(src->handle, 1); + src->state = AL_PAUSED; + } +} + +static ALvoid _alSourceRewind(AL_source *src) +{ + switch (src->state) + { + case AL_PAUSED: + snd_pcm_pause(src->handle, 0); + break; + case AL_PLAYING: + snd_pcm_drop(src->handle); + break; + } + src->state = AL_INITIAL; + src->index = 0; +} + +ALvoid alSourcePlay(ALuint sid) +{ + AL_context *ctx; + AL_source *src; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + if (!(src = _alFindSource(ctx, sid))) + { + _alSetError(AL_INVALID_NAME); + } + else + { + _alSourcePlay(src); + } + + _alcUnlockContext(ctx); +} + +ALvoid alSourceStop(ALuint sid) +{ + AL_context *ctx; + AL_source *src; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + if (!(src = _alFindSource(ctx, sid))) + { + _alSetError(AL_INVALID_NAME); + } + else + { + _alSourceStop(src); + } + + _alcUnlockContext(ctx); +} + +ALvoid alSourcePause(ALuint sid) +{ + AL_context *ctx; + AL_source *src; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + if (!(src = _alFindSource(ctx, sid))) + { + _alSetError(AL_INVALID_NAME); + } + else + { + _alSourcePause(src); + } + + _alcUnlockContext(ctx); +} + +ALvoid alSourceRewind(ALuint sid) +{ + AL_context *ctx; + AL_source *src; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + if (!(src = _alFindSource(ctx, sid))) + { + _alSetError(AL_INVALID_NAME); + } + else + { + _alSourceRewind(src); + } + + _alcUnlockContext(ctx); +} + +ALvoid alSourcePlayv(ALsizei ns, ALuint *ids) +{ + AL_context *ctx; + AL_source **src; + ALsizei i; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + src = alloca(ns * sizeof(AL_source *)); + + for (i = 0; i < ns; i++) + { + if (!(src[i] = _alFindSource(ctx, ids[i]))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + } + + for (i = 0; i < ns; i++) + { + _alSourcePlay(src[i]); + } + +unlock: + _alcUnlockContext(ctx); +} + +ALvoid alSourceStopv(ALsizei ns, ALuint *ids) +{ + AL_context *ctx; + AL_source **src; + ALsizei i; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + src = alloca(ns * sizeof(AL_source *)); + + for (i = 0; i < ns; i++) + { + if (!(src[i] = _alFindSource(ctx, ids[i]))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + } + + for (i = 0; i < ns; i++) + { + _alSourceStop(src[i]); + } + +unlock: + _alcUnlockContext(ctx); +} + +ALvoid alSourcePausev(ALsizei ns, ALuint *ids) +{ + AL_context *ctx; + AL_source **src; + ALsizei i; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + src = alloca(ns * sizeof(AL_source *)); + + for (i = 0; i < ns; i++) + { + if (!(src[i] = _alFindSource(ctx, ids[i]))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + } + + for (i = 0; i < ns; i++) + { + _alSourcePause(src[i]); + } + +unlock: + _alcUnlockContext(ctx); +} + +ALvoid alSourceRewindv(ALsizei ns, ALuint *ids) +{ + AL_context *ctx; + AL_source **src; + ALsizei i; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + src = alloca(ns * sizeof(AL_source *)); + + for (i = 0; i < ns; i++) + { + if (!(src[i] = _alFindSource(ctx, ids[i]))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + } + + for (i = 0; i < ns; i++) + { + _alSourceRewind(src[i]); + } + +unlock: + _alcUnlockContext(ctx); +} diff --git a/src/al_source.c b/src/al_source.c new file mode 100644 index 0000000..c5f462c --- /dev/null +++ b/src/al_source.c @@ -0,0 +1,939 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +#include "al_source.h" +#include "al_vector.h" +#include "al_error.h" +#include "alc_device.h" +#include "alc_context.h" + +#define AL_FIRST_SOURCE_ID 0x4000 + +AL_source *_alFindSource(AL_context *ctx, ALuint cid) +{ + cid -= AL_FIRST_SOURCE_ID; + + if (cid >= ctx->device->subdevs) + { + return 0; + } + + return ctx->sources[cid]; +} + +static AL_source *_alGenSource(AL_context *ctx) +{ + AL_source *src; + + if (!(src = malloc(sizeof(AL_source)))) + { + _alSetError(AL_OUT_OF_MEMORY); + return 0; + } + + src->context = ctx; + src->handle = 0; + src->vol_ctl = 0; + src->send_ctl = 0; + src->subdev = -1; + src->freq = 0; + + src->state = AL_INITIAL; + src->playing = AL_FALSE; + src->buffer = 0; + src->index = 0; + + src->first_q = 0; + src->current_q = 0; + src->last_q = &src->first_q; + + if (!_alcOpenSource(src)) + { + _alcCloseSource(src); + free(src); + _alSetError(AL_OUT_OF_MEMORY); + return 0; + } + + src->relative = AL_FALSE; + src->looping = AL_FALSE; + src->conic = AL_FALSE; + + src->position[0] = 0.0f; + src->position[1] = 0.0f; + src->position[2] = 0.0f; + + src->direction[0] = 0.0f; + src->direction[1] = 0.0f; + src->direction[2] = 0.0f; + + src->velocity[0] = 0.0f; + src->velocity[1] = 0.0f; + src->velocity[2] = 0.0f; + + src->pitch = 1.0f; + src->gain = 1.0f; + src->min_gain = 0.0f; + src->max_gain = 1.0f; + src->reference_distance = 1.0f; + src->rolloff_factor = 1.0f; + src->max_distance = FLT_MAX; + src->cone_inner_angle = 360.0f; + src->cone_outer_angle = 360.0f; + src->cone_outer_gain = 0.0f; + + ctx->sources[src->subdev] = src; + + return src; +} + +ALvoid _alDeleteSource(AL_source *src) +{ + AL_queue *que; + AL_context *ctx = src->context; + + ctx->sources[src->subdev] = 0; + _alcCloseSource(src); + + que = src->first_q; + while (que) + { + AL_queue *next = que->next; + _alUnlockBuffer(que->buffer); + free(que); + que = next; + } + + if (src->buffer) + { + _alUnlockBuffer(src->buffer); + } + + free(src); +} + +ALvoid alGenSources(ALsizei n, ALuint *sources) +{ + AL_context *ctx; + AL_source **temp; + ALsizei i; + + if (n == 0) + { + return; + } + + if (n < 0) + { + _alSetError(AL_INVALID_VALUE); + return; + } + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + temp = alloca(n * sizeof(AL_source *)); + + for (i = 0; i < n; i++) + { + if (!(temp[i] = _alGenSource(ctx))) + { + ALsizei j; + + for (j = 0; j < i; j++) + _alDeleteSource(temp[j]); + + goto unlock; + } + } + + for (i = 0; i < n; i++) + { + sources[i] = temp[i]->subdev + AL_FIRST_SOURCE_ID; + } + +unlock: + _alcUnlockContext(ctx); +} + +ALvoid alDeleteSources(ALsizei n, ALuint* sources) +{ + AL_context *ctx; + AL_source **temp; + ALsizei i; + + if (n == 0) + { + return; + } + + if (n < 0) + { + _alSetError(AL_INVALID_VALUE); + return; + } + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + temp = alloca(n * sizeof(AL_source *)); + + for (i = 0; i < n; i++) + { + if (!(temp[i] = _alFindSource(ctx, sources[i]))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + } + + for (i = 0; i < n; i++) + { + _alDeleteSource(temp[i]); + } + +unlock: + _alcUnlockContext(ctx); +} + +ALboolean alIsSource(ALuint sid) +{ + AL_context *ctx; + ALboolean value; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return AL_FALSE; + } + + _alcLockContext(ctx); + + value = _alFindSource(ctx, sid) ? AL_TRUE : AL_FALSE; + + _alcUnlockContext(ctx); + + return value; +} + +static ALvoid _alNormalizeDirection(AL_source *src) +{ + ALfloat mag = _alVectorMagnitude(src->direction); + + if (mag) + { + src->conic = AL_TRUE; + src->direction[0] /= mag; + src->direction[1] /= mag; + src->direction[2] /= mag; + } + else + { + src->conic = AL_FALSE; + } +} + +ALvoid alSourcei(ALuint sid, ALenum param, ALint value) +{ + AL_context *ctx; + AL_source *src; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + if (!(src = _alFindSource(ctx, sid))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + + switch(param) + { + case AL_SOURCE_RELATIVE: + _alRangedAssignB(src->relative, value); + break; + case AL_LOOPING: + _alRangedAssignB(src->looping, value); + break; + case AL_PITCH: + _alRangedAssign1(src->pitch, value, 0); + break; + case AL_GAIN: + _alRangedAssign1(src->gain, value, 0); + break; + case AL_MIN_GAIN: + _alRangedAssign2(src->min_gain, value, 0, 1); + break; + case AL_MAX_GAIN: + _alRangedAssign2(src->max_gain, value, 0, 1); + break; + case AL_REFERENCE_DISTANCE: + _alRangedAssign1(src->reference_distance, value, 0); + break; + case AL_ROLLOFF_FACTOR: + _alRangedAssign1(src->rolloff_factor, value, 0); + break; + case AL_MAX_DISTANCE: + _alRangedAssign1(src->max_distance, value, 0); + break; + case AL_CONE_INNER_ANGLE: + _alRangedAssign2(src->cone_inner_angle, value, 0, 360); + break; + case AL_CONE_OUTER_ANGLE: + _alRangedAssign2(src->cone_outer_angle, value, 0, 360); + break; + case AL_CONE_OUTER_GAIN: + _alRangedAssign2(src->cone_outer_gain, value, 0, 1); + break; + case AL_BUFFER: + { + AL_buffer *buf; + + if (value) + { + if (!(buf = _alLockBuffer(value))) + { + _alSetError(AL_INVALID_VALUE); + break; + } + } + else + { + buf = 0; + } + + if (src->buffer) + { + _alUnlockBuffer(src->buffer); + } + + src->buffer = buf; + } + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + +unlock: + _alcUnlockContext(ctx); +} + +ALvoid alSourcef(ALuint sid, ALenum param, ALfloat value) +{ + AL_context *ctx; + AL_source *src; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + if (!(src = _alFindSource(ctx, sid))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + + switch(param) + { + case AL_SOURCE_RELATIVE: + _alRangedAssignB(src->relative, value); + break; + case AL_LOOPING: + _alRangedAssignB(src->looping, value); + break; + case AL_PITCH: + _alRangedAssign1(src->pitch, value, 0.0f); + break; + case AL_GAIN: + _alRangedAssign1(src->gain, value, 0.0f); + break; + case AL_MIN_GAIN: + _alRangedAssign2(src->min_gain, value, 0.0f, 1.0f); + break; + case AL_MAX_GAIN: + _alRangedAssign2(src->max_gain, value, 0.0f, 1.0f); + break; + case AL_REFERENCE_DISTANCE: + _alRangedAssign1(src->reference_distance, value, 0.0f); + break; + case AL_ROLLOFF_FACTOR: + _alRangedAssign1(src->rolloff_factor, value, 0.0f); + break; + case AL_MAX_DISTANCE: + _alRangedAssign1(src->max_distance, value, 0.0f); + break; + case AL_CONE_INNER_ANGLE: + _alRangedAssign2(src->cone_inner_angle, value, 0.0f, 360.0f); + break; + case AL_CONE_OUTER_ANGLE: + _alRangedAssign2(src->cone_outer_angle, value, 0.0f, 360.0f); + break; + case AL_CONE_OUTER_GAIN: + _alRangedAssign2(src->cone_outer_gain, value, 0.0f, 1.0f); + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + +unlock: + _alcUnlockContext(ctx); +} + +ALvoid alSource3f(ALuint sid, ALenum param, ALfloat f1, ALfloat f2, ALfloat f3) +{ + AL_context *ctx; + AL_source *src; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + if (!(src = _alFindSource(ctx, sid))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + + switch(param) + { + case AL_POSITION: + src->position[0] = f1; + src->position[1] = f2; + src->position[2] = f3; + break; + case AL_DIRECTION: + src->direction[0] = f1; + src->direction[1] = f2; + src->direction[2] = f3; + _alNormalizeDirection(src); + break; + case AL_VELOCITY: + src->velocity[0] = f1; + src->velocity[1] = f2; + src->velocity[2] = f3; + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + +unlock: + _alcUnlockContext(ctx); +} + +ALvoid alSourcefv(ALuint sid, ALenum param, ALfloat *values) +{ + AL_context *ctx; + AL_source *src; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + if (!(src = _alFindSource(ctx, sid))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + + switch(param) + { + case AL_SOURCE_RELATIVE: + _alRangedAssignB(src->relative, values[0]); + break; + case AL_LOOPING: + _alRangedAssignB(src->looping, values[0]); + break; + case AL_PITCH: + _alRangedAssign1(src->pitch, values[0], 0.0f); + break; + case AL_GAIN: + _alRangedAssign1(src->gain, values[0], 0.0f); + break; + case AL_MIN_GAIN: + _alRangedAssign2(src->min_gain, values[0], 0.0f, 1.0f); + break; + case AL_MAX_GAIN: + _alRangedAssign2(src->max_gain, values[0], 0.0f, 1.0f); + break; + case AL_REFERENCE_DISTANCE: + _alRangedAssign1(src->reference_distance, values[0], 0.0f); + break; + case AL_ROLLOFF_FACTOR: + _alRangedAssign1(src->rolloff_factor, values[0], 0.0f); + break; + case AL_MAX_DISTANCE: + _alRangedAssign1(src->max_distance, values[0], 0.0f); + break; + case AL_CONE_INNER_ANGLE: + _alRangedAssign2(src->cone_inner_angle, values[0], + 0.0f, 360.0f); + break; + case AL_CONE_OUTER_ANGLE: + _alRangedAssign2(src->cone_outer_angle, values[0], + 0.0f, 360.0f); + break; + case AL_CONE_OUTER_GAIN: + _alRangedAssign2(src->cone_outer_gain, values[0], 0.0f, 1.0f); + break; + case AL_POSITION: + src->position[0] = values[0]; + src->position[1] = values[1]; + src->position[2] = values[2]; + break; + case AL_DIRECTION: + src->direction[0] = values[0]; + src->direction[1] = values[1]; + src->direction[2] = values[2]; + _alNormalizeDirection(src); + break; + case AL_VELOCITY: + src->velocity[0] = values[0]; + src->velocity[1] = values[1]; + src->velocity[2] = values[2]; + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + +unlock: + _alcUnlockContext(ctx); +} + +static ALint _alBuffersQueued(AL_source *src) +{ + AL_queue *q; + ALint count = 0; + + for (q = src->first_q; q; q = q->next) + { + count++; + } + + return count; +} + +static ALint _alBuffersProcessed(AL_source *src) +{ + AL_queue *q; + ALint count = 0; + + for (q = src->first_q; q; q = q->next) + { + if (q->state != AL_PROCESSED) + { + break; + } + count++; + } + + return count; +} + +ALvoid alGetSourcei(ALuint sid, ALenum param, ALint *value) +{ + ALint values[3]; + + values[0] = *value; + alGetSourceiv(sid, param, values); + *value = values[0]; +} + +ALvoid alGetSourceiv(ALuint sid, ALenum param, ALint *values) +{ + AL_context *ctx; + AL_source *src; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + if (!(src = _alFindSource(ctx, sid))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + + switch(param) + { + case AL_SOURCE_RELATIVE: + values[0] = src->relative; + break; + case AL_SOURCE_STATE: + values[0] = src->state; + break; + case AL_LOOPING: + values[0] = src->looping; + break; + case AL_PITCH: + values[0] = (ALint)src->pitch; + break; + case AL_GAIN: + values[0] = (ALint)src->gain; + break; + case AL_MIN_GAIN: + values[0] = (ALint)src->min_gain; + break; + case AL_MAX_GAIN: + values[0] = (ALint)src->max_gain; + break; + case AL_REFERENCE_DISTANCE: + values[0] = (ALint)src->reference_distance; + break; + case AL_ROLLOFF_FACTOR: + values[0] = (ALint)src->rolloff_factor; + break; + case AL_MAX_DISTANCE: + values[0] = (ALint)src->max_distance; + break; + case AL_CONE_INNER_ANGLE: + values[0] = (ALint)src->cone_inner_angle; + break; + case AL_CONE_OUTER_ANGLE: + values[0] = (ALint)src->cone_outer_angle; + break; + case AL_CONE_OUTER_GAIN: + values[0] = (ALint)src->cone_outer_gain; + break; + case AL_POSITION: + values[0] = (ALint)src->position[0]; + values[1] = (ALint)src->position[1]; + values[2] = (ALint)src->position[2]; + break; + case AL_DIRECTION: + values[0] = (ALint)src->direction[0]; + values[1] = (ALint)src->direction[1]; + values[2] = (ALint)src->direction[2]; + break; + case AL_VELOCITY: + values[0] = (ALint)src->velocity[0]; + values[1] = (ALint)src->velocity[1]; + values[2] = (ALint)src->velocity[2]; + break; + case AL_BUFFER: + values[0] = src->buffer ? src->buffer->id : 0; + break; + case AL_BUFFERS_QUEUED: + values[0] = _alBuffersQueued(src); + break; + case AL_BUFFERS_PROCESSED: + values[0] = _alBuffersProcessed(src); + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + +unlock: + _alcUnlockContext(ctx); +} + +ALvoid alGetSourcef(ALuint sid, ALenum param, ALfloat *value) +{ + ALfloat values[3]; + + values[0] = *value; + alGetSourcefv(sid, param, values); + *value = values[0]; +} + +ALvoid alGetSource3f(ALuint sid, ALenum param, + ALfloat *f1, ALfloat *f2, ALfloat *f3) +{ + ALfloat values[6]; + + values[0] = *f1; + values[1] = *f2; + values[2] = *f3; + + alGetSourcefv(sid, param, values); + + *f1 = values[0]; + *f2 = values[1]; + *f3 = values[2]; +} + +ALvoid alGetSourcefv(ALuint sid, ALenum param, ALfloat* values) +{ + AL_context *ctx; + AL_source *src; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + if (!(src = _alFindSource(ctx, sid))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + + switch(param) + { + case AL_SOURCE_RELATIVE: + values[0] = src->relative; + break; + case AL_SOURCE_STATE: + values[0] = (ALfloat)src->state; + break; + case AL_LOOPING: + values[0] = (ALfloat)src->looping; + break; + case AL_PITCH: + values[0] = src->pitch; + break; + case AL_GAIN: + values[0] = src->gain; + break; + case AL_MIN_GAIN: + values[0] = src->min_gain; + break; + case AL_MAX_GAIN: + values[0] = src->max_gain; + break; + case AL_REFERENCE_DISTANCE: + values[0] = src->reference_distance; + break; + case AL_ROLLOFF_FACTOR: + values[0] = src->rolloff_factor; + break; + case AL_MAX_DISTANCE: + values[0] = src->max_distance; + break; + case AL_CONE_INNER_ANGLE: + values[0] = src->cone_inner_angle; + break; + case AL_CONE_OUTER_ANGLE: + values[0] = src->cone_outer_angle; + break; + case AL_CONE_OUTER_GAIN: + values[0] = src->cone_outer_gain; + break; + case AL_POSITION: + values[0] = src->position[0]; + values[1] = src->position[1]; + values[2] = src->position[2]; + break; + case AL_DIRECTION: + values[0] = src->direction[0]; + values[1] = src->direction[1]; + values[2] = src->direction[2]; + break; + case AL_VELOCITY: + values[0] = src->velocity[0]; + values[1] = src->velocity[1]; + values[2] = src->velocity[2]; + break; + case AL_BUFFERS_QUEUED: + values[0] = (ALfloat)_alBuffersQueued(src); + break; + case AL_BUFFERS_PROCESSED: + values[0] = (ALfloat)_alBuffersProcessed(src); + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + +unlock: + _alcUnlockContext(ctx); +} + +ALvoid alSourceQueueBuffers(ALuint sid, ALsizei n, ALuint *buffers) +{ + AL_context *ctx; + AL_source *src; + ALsizei i; + AL_queue *first_q; + AL_queue **last_q; + + if (n == 0) + { + return; + } + + if (n < 0) + { + _alSetError(AL_INVALID_VALUE); + return; + } + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + if (!(src = _alFindSource(ctx, sid))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + + first_q = 0; + last_q = &first_q; + + for (i = 0; i < n; i++) + { + AL_buffer *buf; + AL_queue *que; + + if (!buffers[i]) + continue; + + if (!(buf = _alLockBuffer(buffers[i]))) + { + while ((que = first_q)) + { + first_q = que->next; + _alUnlockBuffer(que->buffer); + free(que); + } + + _alSetError(AL_INVALID_NAME); + goto unlock; + } + + if (!(que = malloc(sizeof(AL_queue)))) + { + while ((que = first_q)) + { + first_q = que->next; + _alUnlockBuffer(que->buffer); + free(que); + } + + _alSetError(AL_OUT_OF_MEMORY); + goto unlock; + } + + que->next = 0; + que->buffer = buf; + que->state = AL_PENDING; + + *last_q = que; + last_q = &que->next; + } + + if (first_q) + { + *src->last_q = first_q; + src->last_q = last_q; + } + +unlock: + _alcUnlockContext(ctx); +} + + +ALvoid alSourceUnqueueBuffers(ALuint sid, ALsizei n, ALuint *buffers) +{ + AL_context *ctx; + AL_source *src; + ALsizei i; + + if (n == 0) + { + return; + } + + if (n < 0) + { + _alSetError(AL_INVALID_VALUE); + return; + } + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + if (!(src = _alFindSource(ctx, sid))) + { + _alSetError(AL_INVALID_NAME); + goto unlock; + } + + if (_alBuffersProcessed(src) < n) + { + _alSetError(AL_INVALID_OPERATION); + goto unlock; + } + + for (i = 0; i < n; i++) + { + AL_queue *que = src->first_q; + + src->first_q = que->next; + + buffers[i] = que->buffer->id; + + _alUnlockBuffer(que->buffer); + free(que); + } + +unlock: + _alcUnlockContext(ctx); +} diff --git a/src/al_source.h b/src/al_source.h new file mode 100644 index 0000000..333998f --- /dev/null +++ b/src/al_source.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _AL_SOURCE_H_ +#define _AL_SOURCE_H_ + +#include + +#include +#include + +#include "al_buffer.h" + +typedef struct _AL_queue +{ + struct _AL_queue *next; + AL_buffer *buffer; + ALenum state; +} +AL_queue; + +typedef struct _AL_source +{ + ALCcontext *context; + + snd_pcm_t *handle; + snd_ctl_elem_value_t *vol_ctl; + snd_ctl_elem_value_t *send_ctl; + ALint subdev; + ALuint freq; + + ALenum state; + ALboolean playing; + AL_buffer *buffer; + ALuint index; + + AL_queue *first_q; + AL_queue **last_q; + AL_queue *current_q; + + ALboolean relative; + ALboolean looping; + ALboolean conic; + + ALfloat position[3]; + ALfloat direction[3]; + ALfloat velocity[3]; + + ALfloat pitch; + ALfloat gain; + ALfloat min_gain; + ALfloat max_gain; + ALfloat reference_distance; + ALfloat rolloff_factor; + ALfloat max_distance; + ALfloat cone_inner_angle; + ALfloat cone_outer_angle; + ALfloat cone_outer_gain; +} +AL_source; + +ALvoid _alDeleteSource(AL_source *); +ALvoid _alProcessSource(AL_source *); + +#endif diff --git a/src/al_state.c b/src/al_state.c new file mode 100644 index 0000000..6c26d82 --- /dev/null +++ b/src/al_state.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "alc_context.h" +#include "al_error.h" + +ALboolean alGetBoolean(ALenum param) +{ + ALboolean value = AL_FALSE; + + alGetBooleanv(param, &value); + + return value; +} + +ALint alGetInteger(ALenum param) +{ + ALint value = AL_FALSE; + + alGetIntegerv(param, &value); + + return value; +} + +ALfloat alGetFloat(ALenum param) +{ + ALfloat value = AL_FALSE; + + alGetFloatv(param, &value); + + return value; +} + +ALdouble alGetDouble(ALenum param) +{ + ALdouble value = AL_FALSE; + + alGetDoublev(param, &value); + + return value; +} + +ALvoid alGetBooleanv(ALenum param, ALboolean *values) +{ + AL_context *ctx; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + switch(param) + { + case AL_DOPPLER_FACTOR: + *values = (ctx->doppler_factor != 0.0f) ? + AL_TRUE : AL_FALSE; + break; + case AL_DOPPLER_VELOCITY: + *values = (ctx->doppler_velocity != 0.0f) ? + AL_TRUE : AL_FALSE; + break; + case AL_DISTANCE_MODEL: + *values = (ctx->distance_model != AL_INVERSE_DISTANCE) ? + AL_TRUE : AL_FALSE; + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + + _alcUnlockContext(ctx); +} + +ALvoid alGetIntegerv(ALenum param, ALint *values) +{ + AL_context *ctx; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + switch(param) + { + case AL_DOPPLER_FACTOR: + *values = (ALint)ctx->doppler_factor; + break; + case AL_DOPPLER_VELOCITY: + *values = (ALint)ctx->doppler_velocity; + break; + case AL_DISTANCE_MODEL: + *values = ctx->distance_model; + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + + _alcUnlockContext(ctx); +} + +ALvoid alGetFloatv(ALenum param, ALfloat *values) +{ + AL_context *ctx; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + switch(param) + { + case AL_DOPPLER_FACTOR: + *values = ctx->doppler_factor; + break; + case AL_DOPPLER_VELOCITY: + *values = ctx->doppler_velocity; + break; + case AL_DISTANCE_MODEL: + *values = (ALfloat)ctx->distance_model; + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + + _alcUnlockContext(ctx); +} + +ALvoid alGetDoublev(ALenum param, ALdouble *values) +{ + AL_context *ctx; + + if (!(ctx = _alcCurrentContext)) + { + _alSetError(AL_INVALID_OPERATION); + return; + } + + _alcLockContext(ctx); + + switch(param) + { + case AL_DOPPLER_FACTOR: + *values = (ALdouble)ctx->doppler_factor; + break; + case AL_DOPPLER_VELOCITY: + *values = (ALdouble)ctx->doppler_velocity; + break; + case AL_DISTANCE_MODEL: + *values = (ALdouble)ctx->distance_model; + break; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + + _alcUnlockContext(ctx); +} + +const ALubyte *alGetString(ALenum param) +{ + switch (param) + { + case AL_NO_ERROR: + return "No error"; + case AL_INVALID_NAME: + return "Invalid Name parameter"; + case AL_INVALID_ENUM: + return "Illegal paramater"; + case AL_INVALID_VALUE: + return "Invalid enum parameter value"; + case AL_INVALID_OPERATION: + return "Illegal call"; + case AL_OUT_OF_MEMORY: + return "Unable to allocate memory"; + case AL_VENDOR: + return "Christopher John Purnell"; + case AL_VERSION: + return "0.1.2"; + case AL_RENDERER: + return "EMU10K1"; + case AL_EXTENSIONS: + return ""; + default: + _alSetError(AL_INVALID_ENUM); + break; + } + + return 0; +} diff --git a/src/al_vector.c b/src/al_vector.c new file mode 100644 index 0000000..359b038 --- /dev/null +++ b/src/al_vector.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include "al_vector.h" + +ALfloat _alVectorMagnitude(ALfloat *v) +{ + return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); +} + +ALvoid _alVectorNormalize(ALfloat *d, ALfloat *s) +{ + ALfloat mag; + + if (!(mag = _alVectorMagnitude(s))) + { + d[0] = 0.0f; + d[1] = 0.0f; + d[2] = 0.0f; + } + else + { + d[0] = s[0] / mag; + d[1] = s[1] / mag; + d[2] = s[2] / mag; + } +} + +ALvoid _alVectorCrossProduct(ALfloat *d, ALfloat *v1, ALfloat *v2) +{ + d[0] = v1[1] * v2[2] - v1[2] * v2[1]; + d[1] = v1[2] * v2[0] - v1[0] * v2[2]; + d[2] = v1[0] * v2[1] - v1[1] * v2[0]; +} + +ALfloat _alVectorDotProduct(ALfloat *v1, ALfloat *v2) +{ + return (v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]); +} + +ALvoid _alVectorMatrix(ALfloat *d, ALfloat *s, ALfloat *m) +{ + d[0] = s[0] * m[0] + s[1] * m[3] + s[2] * m[6]; + d[1] = s[0] * m[1] + s[1] * m[4] + s[2] * m[7]; + d[2] = s[0] * m[2] + s[1] * m[5] + s[2] * m[8]; +} diff --git a/src/al_vector.h b/src/al_vector.h new file mode 100644 index 0000000..2f7e21a --- /dev/null +++ b/src/al_vector.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _AL_VECTOR_H_ +#define _AL_VECTOR_H_ + +#include + +ALfloat _alVectorMagnitude(ALfloat *); +ALvoid _alVectorNormalize(ALfloat *, ALfloat *); +ALvoid _alVectorCrossProduct(ALfloat *, ALfloat *, ALfloat *); +ALfloat _alVectorDotProduct(ALfloat *, ALfloat *); +ALvoid _alVectorMatrix(ALfloat *, ALfloat *, ALfloat *); + +#endif diff --git a/src/alc_context.c b/src/alc_context.c new file mode 100644 index 0000000..fc97d3e --- /dev/null +++ b/src/alc_context.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +#include "al_listener.h" +#include "al_source.h" +#include "alc_context.h" +#include "alc_error.h" + +AL_context *_alcCurrentContext = 0; + +static ALCvoid *_alcThread(ALCcontext *cc) +{ + AL_context *ctx = cc; + ALCdevice *dev = ctx->device; + ALuint i; + struct timeval tv; + struct timespec ts; + long ns = 1000000000 / dev->refresh; + + pthread_mutex_lock(&ctx->mutex); + + do + { + gettimeofday(&tv, 0); + + for (i = 0; i < dev->subdevs; i++) + { + AL_source *src; + + if ((src = ctx->sources[i])) + { + _alProcessSource(src); + } + } + + ts.tv_sec = tv.tv_sec; + if ((ts.tv_nsec = (tv.tv_usec * 1000) + ns) >= 1000000000) + { + ts.tv_sec += 1; + ts.tv_nsec -= 1000000000; + } + } + while (pthread_cond_timedwait(&ctx->cond, &ctx->mutex, &ts)); + + pthread_mutex_unlock(&ctx->mutex); + + return 0; +} + +static ALCboolean _alcCreateContext(AL_context *ctx) +{ + ALCdevice *dev = ctx->device; + ALuint i; + + pthread_mutex_init(&ctx->mutex, 0); + + if (!(ctx->sources = malloc(dev->subdevs * sizeof(AL_source*)))) + { + return AL_FALSE; + } + + for (i = 0; i < dev->subdevs; i++) + { + ctx->sources[i] = 0; + } + + if (!dev->sync) + { + + pthread_cond_init(&ctx->cond, 0); + + if (pthread_create(&ctx->thread, 0, _alcThread, ctx)) + { + return AL_FALSE; + } + } + + return ALC_TRUE; +} + +static ALCvoid _alcDestroyContext(AL_context *ctx) +{ + ALCdevice *dev; + ALuint i; + + dev = ctx->device; + + for (i = 0; i < dev->subdevs; i++) + { + AL_source *src; + + if ((src = ctx->sources[i])) + { + _alDeleteSource(src); + } + } + + if (ctx->thread) + { + pthread_cond_signal(&ctx->cond); + + pthread_join(ctx->thread, 0); + + pthread_cond_destroy(&ctx->cond); + } + + if (ctx->sources) + { + free(ctx->sources); + } + + pthread_mutex_destroy(&ctx->mutex); + + free(ctx); +} + +ALCcontext *alcCreateContext(ALCdevice *dev, ALCint *attrlist) +{ + AL_context *ctx; + + if (!dev) + { + _alcSetError(ALC_INVALID_DEVICE); + return 0; + } + + if (!(ctx = malloc(sizeof(AL_context)))) + { + _alcSetError(ALC_OUT_OF_MEMORY); + return 0; + } + + ctx->device = dev; + + while (attrlist) + { + ALCint value; + + switch (*(attrlist++)) + { + case ALC_FREQUENCY: + if ((value = *(attrlist++)) > 0) + { + dev->freq = value; + } + break; + case ALC_REFRESH: + if ((value = *(attrlist++)) > 0) + { + dev->refresh = value; + } + break; + case ALC_SYNC: + dev->sync = *(attrlist++) ? AL_TRUE: AL_FALSE; + break; + default: + attrlist = 0; + break; + } + } + + if (dev->refresh > dev->freq) + { + dev->refresh = dev->freq; + } + + ctx->sources = 0; + ctx->thread = 0; + + _alcLoadSpeakers(ctx->speakers); + _alInitListener(&ctx->listener, ctx->speakers); + + ctx->doppler_factor = 1.0f; + ctx->doppler_velocity = 1.0f; + ctx->distance_model = AL_INVERSE_DISTANCE; + ctx->distance_func = _alDistanceInverse; + + if (_alcCreateContext(ctx)) + return ctx; + + _alcDestroyContext(ctx); + + _alcSetError(ALC_OUT_OF_MEMORY); + + return 0; +} + +ALCenum alcDestroyContext(ALCcontext *cc) +{ + AL_context *ctx; + + if (!(ctx = cc)) + { + _alcSetError(ALC_INVALID_CONTEXT); + return ALC_INVALID_CONTEXT; + } + + if (ctx == _alcCurrentContext) + { + _alcCurrentContext = 0; + } + + _alcDestroyContext(ctx); + + return ALC_NO_ERROR; +} + +ALCenum alcMakeContextCurrent(ALCcontext *cc) +{ + _alcCurrentContext = cc; + + return ALC_NO_ERROR; +} + +ALCcontext *alcGetCurrentContext(ALCvoid) +{ + return _alcCurrentContext; +} + +ALCdevice *alcGetContextsDevice(ALCcontext *cc) +{ + AL_context *ctx; + + if (!(ctx = cc)) + { + _alcSetError(ALC_INVALID_CONTEXT); + return 0; + } + + return ctx->device; +} + +ALCvoid alcSuspendContext(ALCcontext *cc ATTRIBUTE_UNUSED) +{ + /* FIXME */ +} + +ALCvoid *alcProcessContext(ALCcontext *cc) +{ + AL_context *ctx; + ALCdevice *dev; + ALuint i; + + if (!(ctx = cc)) + { + _alcSetError(ALC_INVALID_CONTEXT); + return 0; + } + + if (ctx->thread) + { + return cc; + } + + _alcLockContext(ctx); + + dev = ctx->device; + + for (i = 0; i < dev->subdevs; i++) + { + AL_source *src; + + if ((src = ctx->sources[i])) + { + _alProcessSource(src); + } + } + + _alcUnlockContext(ctx); + + return cc; +} diff --git a/src/alc_context.h b/src/alc_context.h new file mode 100644 index 0000000..70cc045 --- /dev/null +++ b/src/alc_context.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _ALC_CONTEXT_H_ +#define _ALC_CONTEXT_H_ + +#include +#include + +#include +#include + +#include "alc_speaker.h" +#include "alc_device.h" +#include "al_source.h" +#include "al_listener.h" + +typedef struct _AL_context +{ + ALCdevice *device; + AL_source **sources; + + pthread_t thread; + pthread_mutex_t mutex; + pthread_cond_t cond; + + AL_listener listener; + AL_speaker speakers[_ALC_NUM_SPEAKERS]; + + ALfloat doppler_factor; + ALfloat doppler_velocity; + ALenum distance_model; + ALfloat (*distance_func)(AL_source *, ALfloat); +} +AL_context; + +extern AL_context *_alcCurrentContext; + +#define _alcLockContext(ctx) pthread_mutex_lock(&ctx->mutex) +#define _alcUnlockContext(ctx) pthread_mutex_unlock(&ctx->mutex) + +AL_source *_alFindSource(AL_context *, ALuint); + +ALfloat _alDistanceInverse(AL_source *, ALfloat); + +#endif diff --git a/src/alc_device.c b/src/alc_device.c new file mode 100644 index 0000000..a051a1f --- /dev/null +++ b/src/alc_device.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "alc_device.h" +#include "alc_context.h" +#include "alc_error.h" + +#define _ALC_DEF_FREQ 44100 +#define _ALC_DEF_REFRESH 20 +#define _ALC_NUM_PERIODS 2 + +static int live_send_routing[] = { + 0, 1, 2, 3, + 0, 2, 6, 7, + 1, 3, 6, 7 +}; + +static int audigy_send_routing[] = { + 8, 9, 2, 3, 6, 7, 14, 15, + 8, 9, 2, 3, 6, 7, 14, 15, + 8, 9, 2, 3, 6, 7, 14, 15 +}; + +ALCboolean _alcOpenSource(AL_source *src) +{ + snd_pcm_hw_params_t *hw_params; + snd_pcm_info_t *info; + snd_ctl_elem_value_t *route_ctl; + snd_pcm_uframes_t size; + unsigned i; + AL_context *ctx = src->context; + ALCdevice *dev = ctx->device; + int *send_routing; + + if (snd_pcm_open(&src->handle, dev->device, SND_PCM_STREAM_PLAYBACK, + SND_PCM_NONBLOCK)) + return ALC_FALSE; + + snd_pcm_hw_params_alloca(&hw_params); + + if (snd_pcm_hw_params_any(src->handle, hw_params)) + return ALC_FALSE; + if (snd_pcm_hw_params_set_access(src->handle, hw_params, + SND_PCM_ACCESS_MMAP_INTERLEAVED)) + return ALC_FALSE; + if (snd_pcm_hw_params_set_format(src->handle, hw_params, + SND_PCM_FORMAT_S16)) + return ALC_FALSE; + if (snd_pcm_hw_params_set_channels(src->handle, hw_params, 2)) + return ALC_FALSE; + + src->freq = dev->freq; + if (snd_pcm_hw_params_set_rate_near(src->handle, hw_params, + &src->freq, 0)) + return ALC_FALSE; + + if (snd_pcm_hw_params_set_periods(src->handle, hw_params, + _ALC_NUM_PERIODS, 0)) + return ALC_FALSE; + + size = src->freq * _ALC_NUM_PERIODS / dev->refresh; + if (snd_pcm_hw_params_set_buffer_size_near(src->handle, hw_params, + &size)) + return ALC_FALSE; + + if (snd_pcm_hw_params(src->handle, hw_params)) + return ALC_FALSE; + + snd_pcm_info_alloca(&info); + + if (snd_pcm_info(src->handle, info)) + return ALC_FALSE; + + src->subdev = snd_pcm_info_get_subdevice(info); + + if (snd_ctl_elem_value_malloc(&src->vol_ctl)) + return ALC_FALSE; + snd_ctl_elem_value_clear(src->vol_ctl); + snd_ctl_elem_value_set_interface(src->vol_ctl, + SND_CTL_ELEM_IFACE_MIXER); + snd_ctl_elem_value_set_name(src->vol_ctl, + "EMU10K1 PCM Volume"); + snd_ctl_elem_value_set_index(src->vol_ctl, src->subdev); + + if (snd_ctl_elem_value_malloc(&src->send_ctl)) + return ALC_FALSE; + snd_ctl_elem_value_clear(src->send_ctl); + snd_ctl_elem_value_set_interface(src->send_ctl, + SND_CTL_ELEM_IFACE_MIXER); + snd_ctl_elem_value_set_name(src->send_ctl, + "EMU10K1 PCM Send Volume"); + snd_ctl_elem_value_set_index(src->send_ctl, src->subdev); + + snd_ctl_elem_value_alloca(&route_ctl); + snd_ctl_elem_value_clear(route_ctl); + snd_ctl_elem_value_set_interface(route_ctl, + SND_CTL_ELEM_IFACE_MIXER); + snd_ctl_elem_value_set_name(route_ctl, + "EMU10K1 PCM Send Routing"); + snd_ctl_elem_value_set_index(route_ctl, src->subdev); + + send_routing = (dev->send_count == 24) ? + audigy_send_routing : live_send_routing; + + for (i = 0; i < dev->send_count; i++) + { + snd_ctl_elem_value_set_integer(route_ctl, i, send_routing[i]); + snd_ctl_elem_value_set_integer(src->send_ctl, i, 0); + } + + if (snd_ctl_elem_write(dev->ctl, route_ctl)) + return ALC_FALSE; + + return ALC_TRUE; +} + +ALCvoid _alcCloseSource(AL_source *src) +{ + if (src->send_ctl) snd_ctl_elem_value_free(src->send_ctl); + if (src->vol_ctl) snd_ctl_elem_value_free(src->vol_ctl); + if (src->handle) snd_pcm_close(src->handle); +} + +static ALCboolean _alcOpenDevice(ALCdevice *dev) +{ + snd_ctl_elem_info_t *ctl_info; + snd_pcm_info_t *pcm_info; + int card = -1; + + snd_ctl_elem_info_alloca(&ctl_info); + snd_ctl_elem_info_set_interface(ctl_info, SND_CTL_ELEM_IFACE_MIXER); + snd_ctl_elem_info_set_name(ctl_info, "EMU10K1 PCM Send Routing"); + snd_ctl_elem_info_set_index(ctl_info, 0); + + snd_pcm_info_alloca(&pcm_info); + + while (snd_card_next(&card) >= 0 && card >= 0) + { + sprintf(dev->device, "hw:%d", card); + + if (snd_ctl_open(&dev->ctl, dev->device, 0)) + break; + + if (snd_ctl_elem_info(dev->ctl, ctl_info)) + continue; + + dev->send_count = snd_ctl_elem_info_get_count(ctl_info); + + if ((dev->send_count != 12) && (dev->send_count != 24)) + continue; + + if (snd_ctl_pcm_info(dev->ctl, pcm_info)) + break; + + dev->subdevs = snd_pcm_info_get_subdevices_count(pcm_info); + + return ALC_TRUE; + } + + return ALC_FALSE; +} + +static ALCvoid _alcCloseDevice(ALCdevice *dev) +{ + if (dev->ctl) snd_ctl_close(dev->ctl); + free(dev); +} + +ALCdevice *alcOpenDevice(const ALubyte *spec ATTRIBUTE_UNUSED) +{ + ALCdevice *dev; + + if (!(dev = malloc(sizeof(ALCdevice)))) + { + _alcSetError(ALC_OUT_OF_MEMORY); + return 0; + } + + dev->ctl = 0; + dev->sync = ALC_FALSE; + dev->freq = _ALC_DEF_FREQ; + dev->refresh = _ALC_DEF_REFRESH; + + if (_alcOpenDevice(dev)) + return dev; + + _alcCloseDevice(dev); + + _alcSetError(ALC_INVALID_DEVICE); + + return 0; +} + +ALCvoid alcCloseDevice(ALCdevice *dev) +{ + if (dev) + { + _alcCloseDevice(dev); + } + else + { + _alcSetError(ALC_INVALID_DEVICE); + } +} diff --git a/src/alc_device.h b/src/alc_device.h new file mode 100644 index 0000000..7379b42 --- /dev/null +++ b/src/alc_device.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _ALC_DEVICE_H_ +#define _ALC_DEVICE_H_ + +#include + +#include +#include + +#include "al_source.h" + +struct _AL_device +{ + char device[16]; + ALuint subdevs; + snd_ctl_t *ctl; + ALuint send_count; + ALCboolean sync; + ALuint freq; + ALuint refresh; +}; + +ALCboolean _alcOpenSource(AL_source *); +ALCvoid _alcCloseSource(AL_source *); + +#endif diff --git a/src/alc_error.c b/src/alc_error.c new file mode 100644 index 0000000..ca5d06d --- /dev/null +++ b/src/alc_error.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include "alc_error.h" + +static ALCenum __alc_error = ALC_NO_ERROR; + +ALCenum alcGetError(ALCdevice *dev ATTRIBUTE_UNUSED) +{ + ALCenum err = __alc_error; + __alc_error = ALC_NO_ERROR; + return err; +} + +ALCvoid _alcSetError(ALCenum err) +{ + if (__alc_error == ALC_NO_ERROR) + { + __alc_error = err; + } +} diff --git a/src/alc_error.h b/src/alc_error.h new file mode 100644 index 0000000..d0e4f0a --- /dev/null +++ b/src/alc_error.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _ALC_ERROR_H_ +#define _ALC_ERROR_H_ + +#include +#include + +extern ALCvoid _alcSetError(ALCenum); + +#endif diff --git a/src/alc_ext.c b/src/alc_ext.c new file mode 100644 index 0000000..847bbfa --- /dev/null +++ b/src/alc_ext.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include + +ALCboolean alcIsExtensionPresent(ALCdevice *dev ATTRIBUTE_UNUSED, + ALCubyte *name ATTRIBUTE_UNUSED) +{ + return ALC_FALSE; +} + + +ALCvoid *alcGetProcAddress(ALCdevice *dev ATTRIBUTE_UNUSED, + ALubyte *name ATTRIBUTE_UNUSED) +{ + return 0; +} + + +ALCenum alcGetEnumValue(ALCdevice *dev ATTRIBUTE_UNUSED, ALCubyte *name) +{ + return alGetEnumValue(name); +} diff --git a/src/alc_speaker.c b/src/alc_speaker.c new file mode 100644 index 0000000..1576ac1 --- /dev/null +++ b/src/alc_speaker.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +#include "alc_speaker.h" +#include "al_vector.h" + +static AL_speaker _alcDefaultSpeakers[_ALC_NUM_SPEAKERS] = +{ + { 127.5f, { -1.0f, 0.0f, 0.0f } }, /* Front Left */ + { 127.5f, { 1.0f, 0.0f, 0.0f } }, /* Front Right */ + { 0.0f, { 0.0f, 0.0f, 0.0f } }, /* Rear Left */ + { 0.0f, { 0.0f, 0.0f, 0.0f } }, /* Rear Right */ + { 0.0f, { 0.0f, 0.0f, 0.0f } }, /* Center */ + { 0.0f, { 0.0f, 0.0f, 0.0f } }, /* LFE */ + { 0.0f, { 0.0f, 0.0f, 0.0f } }, /* Side Left */ + { 0.0f, { 0.0f, 0.0f, 0.0f } } /* Side Right */ +}; + +ALvoid _alcLoadSpeakers(AL_speaker *speakers) +{ + char *s, buf[1024]; + FILE *fp; + ALuint i; + ALfloat gain; + ALfloat pos[3]; + + memcpy(speakers, _alcDefaultSpeakers, sizeof(_alcDefaultSpeakers)); + + if (!(s = getenv("HOME"))) + { + return; + } + + sprintf(buf, "%s/.openal-speakers", s); + + if (!(fp = fopen(buf, "r"))) + { + return; + } + + while (fgets(buf, 1024, fp)) + { + if ((s = strchr(buf, '#'))) + { + *s = '\0'; + } + + if (sscanf(buf, "%u: %f %f %f %f", &i, &gain, + pos + 0, pos + 1, pos + 2) == 5) + { + if (i >= _ALC_NUM_SPEAKERS) + { + continue; + } + + if (gain < 0.0) + { + gain = 0.0; + } + else if (gain > 1.0) + { + gain = 1.0; + } + + speakers[i].gain = gain * 127.5; + _alVectorNormalize(speakers[i].position, pos); + } + } + + fclose(fp); +} diff --git a/src/alc_speaker.h b/src/alc_speaker.h new file mode 100644 index 0000000..4e1d060 --- /dev/null +++ b/src/alc_speaker.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _ALC_SPEAKER_H_ +#define _ALC_SPEAKER_H_ + +#include +#include + +#define _ALC_NUM_SPEAKERS 8 + +typedef struct _AL_speaker +{ + ALfloat gain; + ALfloat position[3]; +} +AL_speaker; + +ALvoid _alcLoadSpeakers(AL_speaker *); + +#endif diff --git a/src/alc_state.c b/src/alc_state.c new file mode 100644 index 0000000..7a8995e --- /dev/null +++ b/src/alc_state.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include "alc_device.h" +#include "alc_error.h" + +ALCvoid alcGetIntegerv(ALCdevice *dev, ALCenum param, + ALCsizei size, ALCint *data) +{ + if (!data || size < sizeof(ALCint)) + { + _alcSetError(ALC_INVALID_VALUE); + return; + } + + switch(param) + { + case ALC_MAJOR_VERSION: + *data = 1; + break; + case ALC_MINOR_VERSION: + *data = 0; + break; + case ALC_ATTRIBUTES_SIZE: + if (!dev) + { + _alcSetError(ALC_INVALID_DEVICE); + break; + } + *data = 8 * sizeof(ALCint); + break; + case ALC_ALL_ATTRIBUTES: + if (!dev) + { + _alcSetError(ALC_INVALID_DEVICE); + break; + } + if (size < (8 * sizeof(ALCint))) + { + _alcSetError(ALC_INVALID_VALUE); + break; + } + data[0] = ALC_FREQUENCY; + data[1] = dev->freq; + data[2] = ALC_REFRESH; + data[3] = dev->refresh; + data[4] = ALC_SYNC; + data[5] = dev->sync; + data[6] = ALC_INVALID; + data[7] = 0; + break; + default: + _alcSetError(ALC_INVALID_ENUM); + break; + } +} + +const ALubyte *alcGetString(ALCdevice *dev ATTRIBUTE_UNUSED, ALCenum param) +{ + switch (param) + { + case ALC_DEFAULT_DEVICE_SPECIFIER: + return ""; + case ALC_DEVICE_SPECIFIER: + return ""; + case ALC_EXTENSIONS: + return ""; + case ALC_NO_ERROR: + return "No error"; + case ALC_INVALID_DEVICE: + return "There is no accessible sound device/driver/server"; + case ALC_INVALID_CONTEXT: + return "The Context argument does not name a valid context"; + case ALC_INVALID_ENUM: + return "Illegal paramater"; + case ALC_INVALID_VALUE: + return "Invalid enum parameter value"; + case ALC_OUT_OF_MEMORY: + return "Unable to allocate memory"; + default: + _alcSetError(ALC_INVALID_ENUM); + break; + } + + return 0; +} diff --git a/src/alut_main.c b/src/alut_main.c new file mode 100644 index 0000000..f8a9667 --- /dev/null +++ b/src/alut_main.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include + +void alutInit(int *argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) +{ + ALCcontext *ctx; + ALCdevice *dev; + + if (!(dev = alcOpenDevice(0))) + { + return; + } + + if (!(ctx = alcCreateContext(dev, 0))) + { + alcCloseDevice(dev); + return; + } + + alcMakeContextCurrent(ctx); +} + +void alutExit(void) +{ + ALCcontext *ctx; + ALCdevice *dev; + + if (!(ctx = alcGetCurrentContext())) + { + return; + } + + dev = alcGetContextsDevice(ctx); + + alcMakeContextCurrent(0); + alcDestroyContext(ctx); + alcCloseDevice(dev); +} diff --git a/src/alut_wav.c b/src/alut_wav.c new file mode 100644 index 0000000..e99b339 --- /dev/null +++ b/src/alut_wav.c @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2004 Christopher John Purnell + * cjp@lost.org.uk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +#define WAV_RIFF 0x46464952 +#define WAV_WAVE 0x45564157 +#define WAV_fmt 0x20746D66 +#define WAV_data 0x61746164 +#define WAV_smpl 0x6C706D73 + +#define swap16le(D) (D) +#define swap32le(D) (D) + +#elif __BYTE_ORDER == __BIG_ENDIAN + +#define WAV_RIFF 0x52494646 +#define WAV_WAVE 0x57415645 +#define WAV_fmt 0x666D7420 +#define WAV_data 0x64617461 +#define WAV_smpl 0x736D706C + +#define swap16le(D) (((D)<<8) | ((D)>>8)) +#define swap32le(D) ((((D)<<24) | (((D)<<8)&0x00FF0000) | (((D)>>8)&0x0000FF00) | ((D)>>24))) + +#else +#error "Unknown endian" +#endif + +typedef struct +{ + u_int32_t id; + u_int32_t size; + u_int32_t type; + u_int32_t *data; + u_int32_t len; +} +AL_wav_file; + +typedef struct +{ + u_int32_t id; + u_int32_t size; + u_int32_t *data; +} +AL_wav_chunk; + +static ALboolean _alutReadWavHeader(AL_wav_file *file, u_int32_t *memory) +{ + if ((file->id = *(memory++)) != WAV_RIFF) + { + return AL_FALSE; + } + + file->size = swap32le(*(memory++)); + + if (file->size < 4) + { + return AL_FALSE; + } + + if ((file->type = *(memory++)) != WAV_WAVE) + { + return AL_FALSE; + } + + file->data = memory; + file->len = (file->size - 1) >> 2; + + return AL_TRUE; +} + +static ALboolean _alutReadWavChunk(AL_wav_file *file, AL_wav_chunk *chunk) +{ + ALuint len; + + if (file->len < 2) + { + return AL_FALSE; + } + + chunk->id = file->data[0]; + chunk->size = swap32le(file->data[1]); + + len = (chunk->size + 11) >> 2; + + if (file->len < len) + { + return AL_FALSE; + } + + chunk->data = file->data + 2; + + file->data += len; + file->len -= len; + + return AL_TRUE; +} + +ALvoid alutLoadWAVMemory(ALbyte *memory, ALenum *format, ALvoid **data, + ALsizei *size, ALsizei *freq, ALboolean *loop) +{ + AL_wav_file file; + AL_wav_chunk chunk; + ALuint bits = 0; + + *data = 0; + *size = 0; + *freq = 0; + *format = 0; + *loop = 0; + + if (!_alutReadWavHeader(&file, (u_int32_t *)memory)) + { + return; + } + + while (_alutReadWavChunk(&file, &chunk)) + { + u_int16_t *data16 = (u_int16_t *)chunk.data; + + switch (chunk.id) + { + case WAV_fmt: + if (data16[0] != 1) + { + return; + } + + bits = swap16le(data16[7]); + *freq = swap32le(chunk.data[1]); + + switch (swap16le(data16[1])) + { + case 1: + switch (bits) + { + case 8: + *format = AL_FORMAT_MONO8; + break; + case 16: + *format = AL_FORMAT_MONO16; + break; + default: + return; + } + break; + case 2: + switch (bits) + { + case 8: + *format = AL_FORMAT_STEREO8; + break; + case 16: + *format = AL_FORMAT_STEREO16; + break; + default: + return; + } + break; + default: + return; + } + break; + case WAV_data: + if (!bits) + { + return; + } + + *data = malloc(chunk.size); + *size = chunk.size; + +#if __BYTE_ORDER == __LITTLE_ENDIAN + memcpy(*data, chunk.data, chunk.size); +#else + if (bits == 16) + { + u_int16_t *ptr = *data; + ALuint i, s = chunk.size << 1; + + for (i = 0; i < s; i++) + { + ptr[i] = swap16le(data16[i]); + } + } + else + { + memcpy(*data, chunk.data, chunk.size); + } +#endif + break; + case WAV_smpl: + *loop = swap32le(chunk.data[7]); + break; + } + } +} + +ALvoid alutLoadWAVFile(ALbyte *file, ALenum *format, ALvoid **data, + ALsizei *size, ALsizei *freq, ALboolean *loop) +{ + int fd; + void *memory; + struct stat st; + + if ((fd = open(file, O_RDONLY)) < 0) + { + return; + } + + if (!fstat(fd, &st)) + { + memory = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (memory != MAP_FAILED) + { + alutLoadWAVMemory(memory, format, data, + size, freq, loop); + munmap(memory, st.st_size); + } + } + + close(fd); +} + +ALboolean alutLoadWAV(const char *fname, ALvoid **wave, ALsizei *format, ALsizei *size, ALsizei *bits, ALsizei *freq ) +{ + ALboolean loop; + + alutLoadWAVFile((ALubyte *)fname, format, wave, size, freq, &loop); + + if (! *wave) + { + return AL_FALSE; + } + + switch (*format) + { + case AL_FORMAT_MONO8: + case AL_FORMAT_STEREO8: + *bits = 8; + break; + case AL_FORMAT_MONO16: + case AL_FORMAT_STEREO16: + *bits = 16; + break; + } + + return AL_TRUE; +} + +ALvoid alutUnloadWAV(ALenum format ATTRIBUTE_UNUSED, ALvoid *data, + ALsizei size ATTRIBUTE_UNUSED, + ALsizei freq ATTRIBUTE_UNUSED) +{ + if (data) + { + free(data); + } +}