1 /*
2  * Copyright (c) 2002-2010 LWJGL Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'LWJGL' nor the names of
17  *   its contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package org.lwjgl.openal;
33 
34 import static org.lwjgl.openal.AL10.*;
35 import static org.lwjgl.openal.EFX10.*;
36 
37 /**
38  * Utility class for the OpenAL extension ALC_EXT_EFX. Provides functions to check for the extension
39  * and support of various effects and filters.
40  * <p>
41  * Currently supports ALC_EXT_EFX version 1.0 effects and filters.
42  *
43  * @author Ciardhubh <ciardhubh[at]ciardhubh.de>
44  * @version $Revision$
45  * $Id$
46  */
47 public final class EFXUtil {
48 
49     /** Constant for testSupportGeneric to check an effect. */
50     private static final int EFFECT = 1111;
51     /** Constant for testSupportGeneric to check a filter. */
52     private static final int FILTER = 2222;
53 
54     /** Utility class, hidden contructor. */
EFXUtil()55     private EFXUtil() {
56     }
57 
58     /**
59      * Checks if OpenAL implementation is loaded and supports ALC_EXT_EFX.
60      *
61      * @return True if ALC_EXT_EFX is supported, false if not.
62      * @throws OpenALException If OpenAL has not been created yet.
63      */
isEfxSupported()64     public static boolean isEfxSupported() {
65         if (!AL.isCreated()) {
66             throw new OpenALException("OpenAL has not been created.");
67         }
68         return ALC10.alcIsExtensionPresent(AL.getDevice(), ALC_EXT_EFX_NAME);
69     }
70 
71     /**
72      * Tests OpenAL to see whether the given effect type is supported. This is done by creating an
73      * effect of the given type. If creation succeeds the effect is supported.
74      *
75      * @param effectType Type of effect whose support is to be tested, e.g. AL_EFFECT_REVERB.
76      * @return True if it is supported, false if not.
77      * @throws OpenALException If the request fails due to an AL_OUT_OF_MEMORY error or OpenAL has
78      * not been created yet.
79      * @throws IllegalArgumentException effectType is not a valid effect type.
80      */
isEffectSupported(final int effectType)81     public static boolean isEffectSupported(final int effectType) {
82         // Make sure type is a real effect.
83         switch (effectType) {
84             case AL_EFFECT_NULL:
85             case AL_EFFECT_EAXREVERB:
86             case AL_EFFECT_REVERB:
87             case AL_EFFECT_CHORUS:
88             case AL_EFFECT_DISTORTION:
89             case AL_EFFECT_ECHO:
90             case AL_EFFECT_FLANGER:
91             case AL_EFFECT_FREQUENCY_SHIFTER:
92             case AL_EFFECT_VOCAL_MORPHER:
93             case AL_EFFECT_PITCH_SHIFTER:
94             case AL_EFFECT_RING_MODULATOR:
95             case AL_EFFECT_AUTOWAH:
96             case AL_EFFECT_COMPRESSOR:
97             case AL_EFFECT_EQUALIZER:
98                 break;
99             default:
100                 throw new IllegalArgumentException("Unknown or invalid effect type: " + effectType);
101         }
102 
103         return testSupportGeneric(EFFECT, effectType);
104     }
105 
106     /**
107      * Tests OpenAL to see whether the given filter type is supported. This is done by creating a
108      * filter of the given type. If creation succeeds the filter is supported.
109      *
110      * @param filterType Type of filter whose support is to be tested, e.g. AL_FILTER_LOWPASS.
111      * @return True if it is supported, false if not.
112      * @throws OpenALException If the request fails due to an AL_OUT_OF_MEMORY error or OpenAL has
113      * not been created yet.
114      * @throws IllegalArgumentException filterType is not a valid filter type.
115      */
isFilterSupported(final int filterType)116     public static boolean isFilterSupported(final int filterType) {
117         // Make sure type is a real filter.
118         switch (filterType) {
119             case AL_FILTER_NULL:
120             case AL_FILTER_LOWPASS:
121             case AL_FILTER_HIGHPASS:
122             case AL_FILTER_BANDPASS:
123                 break;
124             default:
125                 throw new IllegalArgumentException("Unknown or invalid filter type: " + filterType);
126         }
127 
128         return testSupportGeneric(FILTER, filterType);
129     }
130 
131     /**
132      * Generic test function to see if an EFX object supports a given kind of type. Works for
133      * effects and filters.
134      *
135      * @param objectType Type of object to test. Must be either EFXUtil.EFFECT or EFXUtil.FILTER.
136      * @param typeValue OpenAL type the object should be tested for support, e.g. AL_FILTER_LOWPASS
137      * or AL_EFFECT_REVERB.
138      * @return True if object supports typeValue, false else.
139      */
testSupportGeneric(final int objectType, final int typeValue)140     private static boolean testSupportGeneric(final int objectType, final int typeValue) {
141         // Check for supported objectType.
142         switch (objectType) {
143             case EFFECT:
144             case FILTER:
145                 break;
146             default:
147                 throw new IllegalArgumentException("Invalid objectType: " + objectType);
148         }
149 
150         boolean supported = false;
151         if (isEfxSupported()) {
152 
153             // Try to create object in order to check AL's response.
154             alGetError();
155             int genError;
156             int testObject = 0;
157             try {
158                 switch (objectType) { // Create object based on type
159                     case EFFECT:
160                         testObject = alGenEffects();
161                         break;
162                     case FILTER:
163                         testObject = alGenFilters();
164                         break;
165                     default:
166                         throw new IllegalArgumentException("Invalid objectType: " + objectType);
167                 }
168                 genError = alGetError();
169             } catch (final OpenALException debugBuildException) {
170                 // Hack because OpenALException hides the original error code (short of parsing the
171                 // error message String which would break if it gets changed).
172                 if (debugBuildException.getMessage().contains("AL_OUT_OF_MEMORY")) {
173                     genError = AL_OUT_OF_MEMORY;
174                 } else {
175                     genError = AL_INVALID_OPERATION;
176                 }
177             }
178 
179             if (genError == AL_NO_ERROR) {
180                 // Successfully created, now try to set type.
181                 alGetError();
182                 int setError;
183                 try {
184                     switch (objectType) { // Set based on object type
185                         case EFFECT:
186                             alEffecti(testObject, AL_EFFECT_TYPE, typeValue);
187                             break;
188                         case FILTER:
189                             alFilteri(testObject, AL_FILTER_TYPE, typeValue);
190                             break;
191                         default:
192                             throw new IllegalArgumentException("Invalid objectType: " + objectType);
193                     }
194                     setError = alGetError();
195                 } catch (final OpenALException debugBuildException) {
196                     // Hack because OpenALException hides the original error code (short of parsing
197                     // the error message String which would break when it gets changed).
198                     setError = AL_INVALID_VALUE;
199                 }
200 
201                 if (setError == AL_NO_ERROR) {
202                     supported = true;
203                 }
204 
205                 // Cleanup
206                 try {
207                     switch (objectType) { // Set based on object type
208                         case EFFECT:
209                             alDeleteEffects(testObject);
210                             break;
211                         case FILTER:
212                             alDeleteFilters(testObject);
213                             break;
214                         default:
215                             throw new IllegalArgumentException("Invalid objectType: " + objectType);
216                     }
217                 } catch (final OpenALException debugBuildException) {
218                     // Don't care about cleanup errors.
219                 }
220 
221             } else if (genError == AL_OUT_OF_MEMORY) {
222                 throw new OpenALException(genError);
223             }
224         }
225 
226         return supported;
227     }
228 }
229