OSDN Git Service

Make extension check case insensitive
[mikumikustudio/libgdx-mikumikustudio.git] / backends / gdx-openal / src / com / badlogic / gdx / backends / openal / OpenALAudio.java
1 /*******************************************************************************\r
2  * Copyright 2011 See AUTHORS file.\r
3  * \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  * \r
8  *   http://www.apache.org/licenses/LICENSE-2.0\r
9  * \r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  ******************************************************************************/\r
16 \r
17 package com.badlogic.gdx.backends.openal;\r
18 \r
19 import java.nio.FloatBuffer;\r
20 \r
21 import org.lwjgl.BufferUtils;\r
22 import org.lwjgl.LWJGLException;\r
23 import org.lwjgl.openal.AL;\r
24 import org.lwjgl.openal.AL10;\r
25 \r
26 import com.badlogic.gdx.Audio;\r
27 import com.badlogic.gdx.audio.AudioDevice;\r
28 import com.badlogic.gdx.audio.AudioRecorder;\r
29 import com.badlogic.gdx.files.FileHandle;\r
30 import com.badlogic.gdx.math.MathUtils;\r
31 import com.badlogic.gdx.utils.Array;\r
32 import com.badlogic.gdx.utils.GdxRuntimeException;\r
33 import com.badlogic.gdx.utils.IntArray;\r
34 import com.badlogic.gdx.utils.IntMap;\r
35 import com.badlogic.gdx.utils.LongMap;\r
36 import com.badlogic.gdx.utils.ObjectMap;\r
37 \r
38 import static org.lwjgl.openal.AL10.*;\r
39 \r
40 /** @author Nathan Sweet */\r
41 public class OpenALAudio implements Audio {\r
42         private final int deviceBufferSize;\r
43         private final int deviceBufferCount;\r
44         private IntArray idleSources, allSources;\r
45         private LongMap<Integer> soundIdToSource;\r
46         private IntMap<Long> sourceToSoundId;\r
47         private long nextSoundId = 0;\r
48         private ObjectMap<String, Class<? extends OpenALSound>> extensionToSoundClass = new ObjectMap();\r
49         private ObjectMap<String, Class<? extends OpenALMusic>> extensionToMusicClass = new ObjectMap();\r
50 \r
51         Array<OpenALMusic> music = new Array(false, 1, OpenALMusic.class);\r
52         boolean noDevice = false;\r
53 \r
54         public OpenALAudio () {\r
55                 this(16, 9, 512);\r
56         }\r
57 \r
58         public OpenALAudio (int simultaneousSources, int deviceBufferCount, int deviceBufferSize) {\r
59                 this.deviceBufferSize = deviceBufferSize;\r
60                 this.deviceBufferCount = deviceBufferCount;\r
61 \r
62                 registerSound("ogg", Ogg.Sound.class);\r
63                 registerMusic("ogg", Ogg.Music.class);\r
64                 registerSound("wav", Wav.Sound.class);\r
65                 registerMusic("wav", Wav.Music.class);\r
66                 registerSound("mp3", Mp3.Sound.class);\r
67                 registerMusic("mp3", Mp3.Music.class);\r
68 \r
69                 try {\r
70                         AL.create();\r
71                 } catch (LWJGLException ex) {\r
72                         noDevice = true;\r
73                         ex.printStackTrace();\r
74                         return;\r
75                 }\r
76 \r
77                 allSources = new IntArray(false, simultaneousSources);\r
78                 for (int i = 0; i < simultaneousSources; i++) {\r
79                         int sourceID = alGenSources();\r
80                         if (alGetError() != AL_NO_ERROR) break;\r
81                         allSources.add(sourceID);\r
82                 }\r
83                 idleSources = new IntArray(allSources);\r
84                 soundIdToSource = new LongMap<Integer>();\r
85                 sourceToSoundId = new IntMap<Long>();\r
86 \r
87                 FloatBuffer orientation = (FloatBuffer)BufferUtils.createFloatBuffer(6)\r
88                         .put(new float[] {0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f}).flip();\r
89                 alListener(AL_ORIENTATION, orientation);\r
90                 FloatBuffer velocity = (FloatBuffer)BufferUtils.createFloatBuffer(3).put(new float[] {0.0f, 0.0f, 0.0f}).flip();\r
91                 alListener(AL_VELOCITY, velocity);\r
92                 FloatBuffer position = (FloatBuffer)BufferUtils.createFloatBuffer(3).put(new float[] {0.0f, 0.0f, 0.0f}).flip();\r
93                 alListener(AL_POSITION, position);\r
94         }\r
95 \r
96         public void registerSound (String extension, Class<? extends OpenALSound> soundClass) {\r
97                 if (extension == null) throw new IllegalArgumentException("extension cannot be null.");\r
98                 if (soundClass == null) throw new IllegalArgumentException("soundClass cannot be null.");\r
99                 extensionToSoundClass.put(extension, soundClass);\r
100         }\r
101 \r
102         public void registerMusic (String extension, Class<? extends OpenALMusic> musicClass) {\r
103                 if (extension == null) throw new IllegalArgumentException("extension cannot be null.");\r
104                 if (musicClass == null) throw new IllegalArgumentException("musicClass cannot be null.");\r
105                 extensionToMusicClass.put(extension, musicClass);\r
106         }\r
107 \r
108         public OpenALSound newSound (FileHandle file) {\r
109                 if (file == null) throw new IllegalArgumentException("file cannot be null.");\r
110                 Class<? extends OpenALSound> soundClass = extensionToSoundClass.get(file.extension().toLowerCase());\r
111                 if (soundClass == null) throw new GdxRuntimeException("Unknown file extension for sound: " + file);\r
112                 try {\r
113                         return soundClass.getConstructor(new Class[] {OpenALAudio.class, FileHandle.class}).newInstance(this, file);\r
114                 } catch (Exception ex) {\r
115                         throw new GdxRuntimeException("Error creating sound " + soundClass.getName() + " for file: " + file, ex);\r
116                 }\r
117         }\r
118 \r
119         public OpenALMusic newMusic (FileHandle file) {\r
120                 if (file == null) throw new IllegalArgumentException("file cannot be null.");\r
121                 Class<? extends OpenALMusic> musicClass = extensionToMusicClass.get(file.extension().toLowerCase());\r
122                 if (musicClass == null) throw new GdxRuntimeException("Unknown file extension for music: " + file);\r
123                 try {\r
124                         return musicClass.getConstructor(new Class[] {OpenALAudio.class, FileHandle.class}).newInstance(this, file);\r
125                 } catch (Exception ex) {\r
126                         throw new GdxRuntimeException("Error creating music " + musicClass.getName() + " for file: " + file, ex);\r
127                 }\r
128         }\r
129 \r
130         int obtainSource (boolean isMusic) {\r
131                 if (noDevice) return 0;\r
132                 for (int i = 0, n = idleSources.size; i < n; i++) {\r
133                         int sourceId = idleSources.get(i);\r
134                         int state = alGetSourcei(sourceId, AL_SOURCE_STATE);\r
135                         if (state != AL_PLAYING && state != AL_PAUSED) {\r
136                                 if (isMusic) {\r
137                                         idleSources.removeIndex(i);\r
138                                 } else {\r
139                                         if (sourceToSoundId.containsKey(sourceId)) {\r
140                                                 long soundId = sourceToSoundId.get(sourceId);\r
141                                                 sourceToSoundId.remove(sourceId);\r
142                                                 soundIdToSource.remove(soundId);\r
143                                         }\r
144 \r
145                                         long soundId = nextSoundId++;\r
146                                         sourceToSoundId.put(sourceId, soundId);\r
147                                         soundIdToSource.put(soundId, sourceId);\r
148                                 }\r
149                                 alSourceStop(sourceId);\r
150                                 alSourcei(sourceId, AL_BUFFER, 0);\r
151                                 AL10.alSourcef(sourceId, AL10.AL_GAIN, 1);\r
152                                 AL10.alSourcef(sourceId, AL10.AL_PITCH, 1);\r
153                                 AL10.alSource3f(sourceId, AL10.AL_POSITION, 0, 0, 1f);\r
154                                 return sourceId;\r
155                         }\r
156                 }\r
157                 return -1;\r
158         }\r
159 \r
160         void freeSource (int sourceID) {\r
161                 if (noDevice) return;\r
162                 alSourceStop(sourceID);\r
163                 alSourcei(sourceID, AL_BUFFER, 0);\r
164                 if (sourceToSoundId.containsKey(sourceID)) {\r
165                         long soundId = sourceToSoundId.remove(sourceID);\r
166                         soundIdToSource.remove(soundId);\r
167                 }\r
168                 idleSources.add(sourceID);\r
169         }\r
170 \r
171         void freeBuffer (int bufferID) {\r
172                 if (noDevice) return;\r
173                 for (int i = 0, n = idleSources.size; i < n; i++) {\r
174                         int sourceID = idleSources.get(i);\r
175                         if (alGetSourcei(sourceID, AL_BUFFER) == bufferID) {\r
176                                 if (sourceToSoundId.containsKey(sourceID)) {\r
177                                         long soundId = sourceToSoundId.remove(sourceID);\r
178                                         soundIdToSource.remove(soundId);\r
179                                 }\r
180                                 alSourceStop(sourceID);\r
181                                 alSourcei(sourceID, AL_BUFFER, 0);\r
182                         }\r
183                 }\r
184         }\r
185 \r
186         void stopSourcesWithBuffer (int bufferID) {\r
187                 if (noDevice) return;\r
188                 for (int i = 0, n = idleSources.size; i < n; i++) {\r
189                         int sourceID = idleSources.get(i);\r
190                         if (alGetSourcei(sourceID, AL_BUFFER) == bufferID) {\r
191                                 if (sourceToSoundId.containsKey(sourceID)) {\r
192                                         long soundId = sourceToSoundId.remove(sourceID);\r
193                                         soundIdToSource.remove(soundId);\r
194                                 }\r
195                                 alSourceStop(sourceID);\r
196                         }\r
197                 }\r
198         }\r
199 \r
200         public void update () {\r
201                 if (noDevice) return;\r
202                 for (int i = 0; i < music.size; i++)\r
203                         music.items[i].update();\r
204         }\r
205 \r
206         public long getSoundId (int sourceId) {\r
207                 if (!sourceToSoundId.containsKey(sourceId)) return -1;\r
208                 return sourceToSoundId.get(sourceId);\r
209         }\r
210 \r
211         public void stopSound (long soundId) {\r
212                 if (!soundIdToSource.containsKey(soundId)) return;\r
213                 int sourceId = soundIdToSource.get(soundId);\r
214                 alSourceStop(sourceId);\r
215         }\r
216 \r
217         public void setSoundGain (long soundId, float volume) {\r
218                 if (!soundIdToSource.containsKey(soundId)) return;\r
219                 int sourceId = soundIdToSource.get(soundId);\r
220                 AL10.alSourcef(sourceId, AL10.AL_GAIN, volume);\r
221         }\r
222 \r
223         public void setSoundLooping (long soundId, boolean looping) {\r
224                 if (!soundIdToSource.containsKey(soundId)) return;\r
225                 int sourceId = soundIdToSource.get(soundId);\r
226                 alSourcei(sourceId, AL10.AL_LOOPING, looping ? AL10.AL_TRUE : AL10.AL_FALSE);\r
227         }\r
228 \r
229         public void setSoundPitch (long soundId, float pitch) {\r
230                 if (!soundIdToSource.containsKey(soundId)) return;\r
231                 int sourceId = soundIdToSource.get(soundId);\r
232                 AL10.alSourcef(sourceId, AL10.AL_PITCH, pitch);\r
233         }\r
234 \r
235         public void setSoundPan (long soundId, float pan, float volume) {\r
236                 if (!soundIdToSource.containsKey(soundId)) return;\r
237                 int sourceId = soundIdToSource.get(soundId);\r
238 \r
239                 AL10.alSource3f(sourceId, AL10.AL_POSITION, MathUtils.cos((pan - 1) * MathUtils.PI / 2), 0,\r
240                         MathUtils.sin((pan + 1) * MathUtils.PI / 2));\r
241                 AL10.alSourcef(sourceId, AL10.AL_GAIN, volume);\r
242         }\r
243 \r
244         public void dispose () {\r
245                 if (noDevice) return;\r
246                 for (int i = 0, n = allSources.size; i < n; i++) {\r
247                         int sourceID = allSources.get(i);\r
248                         int state = alGetSourcei(sourceID, AL_SOURCE_STATE);\r
249                         if (state != AL_STOPPED) alSourceStop(sourceID);\r
250                         alDeleteSources(sourceID);\r
251                 }\r
252 \r
253                 sourceToSoundId.clear();\r
254                 soundIdToSource.clear();\r
255 \r
256                 AL.destroy();\r
257                 while (AL.isCreated()) {\r
258                         try {\r
259                                 Thread.sleep(10);\r
260                         } catch (InterruptedException e) {\r
261                         }\r
262                 }\r
263         }\r
264 \r
265         public AudioDevice newAudioDevice (int sampleRate, final boolean isMono) {\r
266                 if (noDevice) return new AudioDevice() {\r
267                         @Override\r
268                         public void writeSamples (float[] samples, int offset, int numSamples) {\r
269                         }\r
270 \r
271                         @Override\r
272                         public void writeSamples (short[] samples, int offset, int numSamples) {\r
273                         }\r
274 \r
275                         @Override\r
276                         public void setVolume (float volume) {\r
277                         }\r
278 \r
279                         @Override\r
280                         public boolean isMono () {\r
281                                 return isMono;\r
282                         }\r
283 \r
284                         @Override\r
285                         public int getLatency () {\r
286                                 return 0;\r
287                         }\r
288 \r
289                         @Override\r
290                         public void dispose () {\r
291                         }\r
292                 };\r
293                 return new OpenALAudioDevice(this, sampleRate, isMono, deviceBufferSize, deviceBufferCount);\r
294         }\r
295 \r
296         public AudioRecorder newAudioRecorder (int samplingRate, boolean isMono) {\r
297                 if (noDevice) return new AudioRecorder() {\r
298                         @Override\r
299                         public void read (short[] samples, int offset, int numSamples) {\r
300                         }\r
301 \r
302                         @Override\r
303                         public void dispose () {\r
304                         }\r
305                 };\r
306                 return new JavaSoundAudioRecorder(samplingRate, isMono);\r
307         }\r
308 }\r