OSDN Git Service

[added] OpenALAudioDevice.
authornathan.sweet <nathan.sweet@6c4fd544-2939-11df-bb46-9574ba5d0bfa>
Sun, 23 Oct 2011 20:45:00 +0000 (20:45 +0000)
committernathan.sweet <nathan.sweet@6c4fd544-2939-11df-bb46-9574ba5d0bfa>
Sun, 23 Oct 2011 20:45:00 +0000 (20:45 +0000)
backends/gdx-backend-lwjgl/src/com/badlogic/gdx/backends/lwjgl/LwjglPreferences.java
backends/gdx-openal/src/com/badlogic/gdx/backends/openal/JavaSoundAudioDevice.java [deleted file]
backends/gdx-openal/src/com/badlogic/gdx/backends/openal/OpenALAudio.java
backends/gdx-openal/src/com/badlogic/gdx/backends/openal/OpenALAudioDevice.java [new file with mode: 0644]
gdx/src/com/badlogic/gdx/ApplicationAdapter.java
gdx/src/com/badlogic/gdx/graphics/glutils/ShapeRenderer.java

index 543751c..dd4d82e 100644 (file)
@@ -28,6 +28,7 @@ import java.util.Properties;
 import com.badlogic.gdx.Gdx;\r
 import com.badlogic.gdx.Preferences;\r
 import com.badlogic.gdx.files.FileHandle;\r
+import com.badlogic.gdx.utils.GdxRuntimeException;\r
 \r
 public class LwjglPreferences implements Preferences {\r
        private final String name;\r
@@ -173,11 +174,13 @@ public class LwjglPreferences implements Preferences {
        @Override\r
        public void flush () {\r
                if (Gdx.files == null) return;\r
+               FileHandle file = Gdx.files.external(LwjglPreferences.this.name);\r
                OutputStream out = null;\r
                try {\r
-                       out = new BufferedOutputStream(Gdx.files.external(LwjglPreferences.this.name).write(false));\r
+                       out = new BufferedOutputStream(file.write(false));\r
                        properties.storeToXML(out, null);\r
-               } catch (Throwable t) {\r
+               } catch (Exception ex) {\r
+                       throw new GdxRuntimeException("Error writing preferences: " + file, ex);\r
                } finally {\r
                        if (out != null) try {\r
                                out.close();\r
diff --git a/backends/gdx-openal/src/com/badlogic/gdx/backends/openal/JavaSoundAudioDevice.java b/backends/gdx-openal/src/com/badlogic/gdx/backends/openal/JavaSoundAudioDevice.java
deleted file mode 100644 (file)
index f580fef..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*******************************************************************************\r
- * Copyright 2011 See AUTHORS file.\r
- * \r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- * \r
- *   http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- ******************************************************************************/\r
-\r
-package com.badlogic.gdx.backends.openal;\r
-\r
-import javax.sound.sampled.AudioFormat;\r
-import javax.sound.sampled.AudioSystem;\r
-import javax.sound.sampled.SourceDataLine;\r
-\r
-import com.badlogic.gdx.audio.AudioDevice;\r
-import com.badlogic.gdx.utils.GdxRuntimeException;\r
-\r
-/** @author mzechner */\r
-public class JavaSoundAudioDevice implements AudioDevice {\r
-       private SourceDataLine line;\r
-       private final boolean isMono;\r
-       private byte[] bytes = new byte[44100 * 2 * 2];\r
-\r
-       public JavaSoundAudioDevice (int samplingRate, boolean isMono) {\r
-               this.isMono = isMono;\r
-\r
-               try {\r
-                       AudioFormat format = new AudioFormat(samplingRate, 16, isMono ? 1 : 2, true, false);\r
-                       line = AudioSystem.getSourceDataLine(format);\r
-                       line.open(format, 2048 * 10);// Math.min(2048*10, samplingRate / 5) * 2);\r
-                       line.start();\r
-               } catch (Exception ex) {\r
-                       throw new GdxRuntimeException("Error creating JavaSoundAudioDevice.", ex);\r
-               }\r
-       }\r
-\r
-       public void dispose () {\r
-               line.drain();\r
-               line.close();\r
-       }\r
-\r
-       public boolean isMono () {\r
-               return isMono;\r
-       }\r
-\r
-       public void writeSamples (short[] samples, int offset, int numSamples) {\r
-               if (bytes.length < samples.length * 2) bytes = new byte[samples.length * 2];\r
-\r
-               for (int i = offset, j = 0; i < offset + numSamples; i++, j += 2) {\r
-                       short value = samples[i];\r
-                       bytes[j] = (byte)(value & 0xff);\r
-                       bytes[j + 1] = (byte)(value >> 8);\r
-               }\r
-\r
-               int writtenBytes = line.write(bytes, 0, numSamples * 2);\r
-               while (writtenBytes != numSamples * 2)\r
-                       writtenBytes += line.write(bytes, writtenBytes, numSamples * 2 - writtenBytes);\r
-       }\r
-\r
-       public void writeSamples (float[] samples, int offset, int numSamples) {\r
-               if (bytes.length < samples.length * 2) bytes = new byte[samples.length * 2];\r
-\r
-               for (int i = offset, j = 0; i < offset + numSamples; i++, j += 2) {\r
-                       float fValue = samples[i];\r
-                       if (fValue > 1) fValue = 1;\r
-                       if (fValue < -1) fValue = -1;\r
-                       short value = (short)(fValue * Short.MAX_VALUE);\r
-                       bytes[j] = (byte)(value & 0xff);\r
-                       bytes[j + 1] = (byte)(value >> 8);\r
-               }\r
-\r
-               int writtenBytes = line.write(bytes, 0, numSamples * 2);\r
-               while (writtenBytes != numSamples * 2)\r
-                       writtenBytes += line.write(bytes, writtenBytes, numSamples * 2 - writtenBytes);\r
-       }\r
-\r
-       @Override\r
-       public int getLatency () {\r
-               return 0;\r
-       }\r
-}\r
index c2cc954..723dfe8 100644 (file)
@@ -143,12 +143,12 @@ public class OpenALAudio implements Audio {
                                if (isMusic) {\r
                                        idleSources.removeIndex(i);\r
                                } else {\r
-                                       if(sourceToSoundId.containsKey(sourceId)) {\r
+                                       if (sourceToSoundId.containsKey(sourceId)) {\r
                                                long soundId = sourceToSoundId.get(sourceId);\r
                                                sourceToSoundId.remove(sourceId);\r
                                                soundIdToSource.remove(soundId);\r
                                        }\r
-                                       \r
+\r
                                        long soundId = nextSoundId++;\r
                                        sourceToSoundId.put(sourceId, soundId);\r
                                        soundIdToSource.put(soundId, sourceId);\r
@@ -167,7 +167,7 @@ public class OpenALAudio implements Audio {
        void freeSource (int sourceID) {\r
                alSourceStop(sourceID);\r
                alSourcei(sourceID, AL_BUFFER, 0);\r
-               if(sourceToSoundId.containsKey(sourceID)) {\r
+               if (sourceToSoundId.containsKey(sourceID)) {\r
                        long soundId = sourceToSoundId.remove(sourceID);\r
                        soundIdToSource.remove(soundId);\r
                }\r
@@ -180,7 +180,7 @@ public class OpenALAudio implements Audio {
                        if (alGetSourcei(sourceID, AL_BUFFER) == bufferID) {\r
                                long soundId = sourceToSoundId.remove(sourceID);\r
                                soundIdToSource.remove(soundId);\r
-                               \r
+\r
                                alSourceStop(sourceID);\r
                                alSourcei(sourceID, AL_BUFFER, 0);\r
                        }\r
@@ -193,7 +193,7 @@ public class OpenALAudio implements Audio {
                        if (alGetSourcei(sourceID, AL_BUFFER) == bufferID) {\r
                                long soundId = sourceToSoundId.remove(sourceID);\r
                                soundIdToSource.remove(soundId);\r
-                               \r
+\r
                                alSourceStop(sourceID);\r
                        }\r
                }\r
@@ -204,42 +204,42 @@ public class OpenALAudio implements Audio {
                        music.items[i].update();\r
        }\r
 \r
-       public long getSoundId(int sourceId) {\r
-               if(!sourceToSoundId.containsKey(sourceId)) return -1;\r
+       public long getSoundId (int sourceId) {\r
+               if (!sourceToSoundId.containsKey(sourceId)) return -1;\r
                return sourceToSoundId.get(sourceId);\r
        }\r
-       \r
-       public void stopSound(long soundId) {\r
-               if(!soundIdToSource.containsKey(soundId)) return;\r
+\r
+       public void stopSound (long soundId) {\r
+               if (!soundIdToSource.containsKey(soundId)) return;\r
                int sourceId = soundIdToSource.get(soundId);\r
                alSourceStop(sourceId);\r
        }\r
-       \r
-       public void setSoundGain(long soundId, float volume) {\r
-               if(!soundIdToSource.containsKey(soundId)) return;\r
+\r
+       public void setSoundGain (long soundId, float volume) {\r
+               if (!soundIdToSource.containsKey(soundId)) return;\r
                int sourceId = soundIdToSource.get(soundId);\r
                AL10.alSourcef(sourceId, AL10.AL_GAIN, volume);\r
        }\r
 \r
        public void setSoundLooping (long soundId, boolean looping) {\r
-               if(!soundIdToSource.containsKey(soundId)) return;\r
+               if (!soundIdToSource.containsKey(soundId)) return;\r
                int sourceId = soundIdToSource.get(soundId);\r
-               alSourcei(sourceId, AL10.AL_LOOPING, looping?AL10.AL_TRUE:AL10.AL_FALSE);\r
+               alSourcei(sourceId, AL10.AL_LOOPING, looping ? AL10.AL_TRUE : AL10.AL_FALSE);\r
        }\r
-       \r
-       public void setSoundPitch(long soundId, float pitch) {\r
-               if(!soundIdToSource.containsKey(soundId)) return;\r
+\r
+       public void setSoundPitch (long soundId, float pitch) {\r
+               if (!soundIdToSource.containsKey(soundId)) return;\r
                int sourceId = soundIdToSource.get(soundId);\r
                AL10.alSourcef(sourceId, AL10.AL_PITCH, pitch);\r
        }\r
-       \r
-       public void setSoundPan(long soundId, float pan, float volume) {\r
-               if(!soundIdToSource.containsKey(soundId)) return;\r
+\r
+       public void setSoundPan (long soundId, float pan, float volume) {\r
+               if (!soundIdToSource.containsKey(soundId)) return;\r
                int sourceId = soundIdToSource.get(soundId);\r
-               \r
-               AL10.alSource3f(sourceId, AL10.AL_POSITION, -pan, 0, 0); \r
+\r
+               AL10.alSource3f(sourceId, AL10.AL_POSITION, -pan, 0, 0);\r
        }\r
-       \r
+\r
        public void dispose () {\r
                for (int i = 0, n = allSources.size; i < n; i++) {\r
                        int sourceID = allSources.get(i);\r
@@ -250,9 +250,9 @@ public class OpenALAudio implements Audio {
 \r
                sourceToSoundId.clear();\r
                soundIdToSource.clear();\r
-               \r
+\r
                AL.destroy();\r
-               while(AL.isCreated()) {\r
+               while (AL.isCreated()) {\r
                        try {\r
                                Thread.sleep(10);\r
                        } catch (InterruptedException e) {\r
@@ -260,12 +260,12 @@ public class OpenALAudio implements Audio {
                }\r
        }\r
 \r
-       public AudioDevice newAudioDevice (int samplingRate, boolean isMono) {\r
-               // BOZO - Write OpenAL device.\r
-               return new JavaSoundAudioDevice(samplingRate, isMono);\r
+       public AudioDevice newAudioDevice (int sampleRate, boolean isMono) {\r
+               return new OpenALAudioDevice(this, sampleRate, isMono);\r
        }\r
 \r
        public AudioRecorder newAudioRecoder (int samplingRate, boolean isMono) {\r
+               // BOZO - Write OpenAL recorder.\r
                return new JavaSoundAudioRecorder(samplingRate, isMono);\r
        }\r
 \r
diff --git a/backends/gdx-openal/src/com/badlogic/gdx/backends/openal/OpenALAudioDevice.java b/backends/gdx-openal/src/com/badlogic/gdx/backends/openal/OpenALAudioDevice.java
new file mode 100644 (file)
index 0000000..874e778
--- /dev/null
@@ -0,0 +1,179 @@
+\r
+package com.badlogic.gdx.backends.openal;\r
+\r
+import java.nio.ByteBuffer;\r
+import java.nio.IntBuffer;\r
+\r
+import org.lwjgl.BufferUtils;\r
+import org.lwjgl.openal.AL11;\r
+\r
+import com.badlogic.gdx.audio.AudioDevice;\r
+import com.badlogic.gdx.math.MathUtils;\r
+import com.badlogic.gdx.utils.GdxRuntimeException;\r
+\r
+import static org.lwjgl.openal.AL10.*;\r
+\r
+/** @author Nathan Sweet */\r
+public class OpenALAudioDevice implements AudioDevice {\r
+       static private final int bufferSize = 512;\r
+       static private final int bufferCount = 9;\r
+       static private final int bytesPerSample = 2;\r
+       static private final ByteBuffer tempBuffer = BufferUtils.createByteBuffer(bufferSize);\r
+\r
+       private final OpenALAudio audio;\r
+       private final int channels;\r
+       private IntBuffer buffers;\r
+       private int sourceID = -1;\r
+       private int format, sampleRate;\r
+       private boolean isPlaying;\r
+       private float volume = 1;\r
+       private float renderedSeconds, secondsPerBuffer;\r
+       private byte[] bytes;\r
+\r
+       public OpenALAudioDevice (OpenALAudio audio, int sampleRate, boolean isMono) {\r
+               this.audio = audio;\r
+               channels = isMono ? 1 : 2;\r
+               this.format = channels > 1 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;\r
+               this.sampleRate = sampleRate;\r
+               secondsPerBuffer = (float)bufferSize / bytesPerSample / channels / sampleRate;\r
+       }\r
+\r
+       public void writeSamples (short[] samples, int offset, int numSamples) {\r
+               if (bytes == null || bytes.length < numSamples * 2) bytes = new byte[numSamples * 2];\r
+               for (int i = offset, ii = 0; i < numSamples; i++) {\r
+                       short sample = samples[i];\r
+                       bytes[ii++] = (byte)(sample & 0xFF);\r
+                       bytes[ii++] = (byte)((sample >> 8) & 0xFF);\r
+               }\r
+               writeSamples(bytes, 0, numSamples * 2);\r
+       }\r
+\r
+       public void writeSamples (float[] samples, int offset, int numSamples) {\r
+               if (bytes == null || bytes.length < numSamples * 2) bytes = new byte[numSamples * 2];\r
+               for (int i = offset, ii = 0; i < numSamples; i++) {\r
+                       float floatSample = samples[i];\r
+                       floatSample = MathUtils.clamp(floatSample, -1f, 1f);\r
+                       int intSample = (int)(floatSample * 32767);\r
+                       bytes[ii++] = (byte)(intSample & 0xFF);\r
+                       bytes[ii++] = (byte)((intSample >> 8) & 0xFF);\r
+               }\r
+               writeSamples(bytes, 0, numSamples * 2);\r
+       }\r
+\r
+       public void writeSamples (byte[] data, int offset, int length) {\r
+               if (length < 0) throw new IllegalArgumentException("length cannot be < 0.");\r
+\r
+               if (sourceID == -1) {\r
+                       sourceID = audio.obtainSource(true);\r
+                       if (sourceID == -1) return;\r
+                       if (buffers == null) {\r
+                               buffers = BufferUtils.createIntBuffer(bufferCount);\r
+                               alGenBuffers(buffers);\r
+                               if (alGetError() != AL_NO_ERROR) throw new GdxRuntimeException("Unabe to allocate audio buffers.");\r
+                       }\r
+                       alSourcei(sourceID, AL_LOOPING, AL_FALSE);\r
+                       alSourcef(sourceID, AL_GAIN, volume);\r
+                       // Queue empty buffers.\r
+                       tempBuffer.clear().flip();\r
+                       for (int i = 0; i < bufferCount; i++) {\r
+                               int bufferID = buffers.get(i);\r
+                               alBufferData(bufferID, format, tempBuffer, sampleRate);\r
+                               alSourceQueueBuffers(sourceID, bufferID);\r
+                       }\r
+                       alSourcePlay(sourceID);\r
+                       isPlaying = true;\r
+                       return;\r
+               }\r
+\r
+               while (length > 0) {\r
+                       int written = fillBuffer(data, offset, length);\r
+                       length -= written;\r
+                       offset += written;\r
+               }\r
+       }\r
+\r
+       /** Blocks until some of the data could be buffered. */\r
+       private int fillBuffer (byte[] data, int offset, int length) {\r
+               int written = Math.min(bufferSize, length);\r
+\r
+               outer:\r
+               while (true) {\r
+                       int buffers = alGetSourcei(sourceID, AL_BUFFERS_PROCESSED);\r
+                       while (buffers-- > 0) {\r
+                               int bufferID = alSourceUnqueueBuffers(sourceID);\r
+                               if (bufferID == AL_INVALID_VALUE) break;\r
+                               renderedSeconds += secondsPerBuffer;\r
+\r
+                               tempBuffer.clear();\r
+                               tempBuffer.put(data, offset, written).flip();\r
+                               alBufferData(bufferID, format, tempBuffer, sampleRate);\r
+\r
+                               alSourceQueueBuffers(sourceID, bufferID);\r
+                               break outer;\r
+                       }\r
+                       // Wait for buffer to be free.\r
+                       try {\r
+                               Thread.sleep((long)(1000 * secondsPerBuffer / bufferCount));\r
+                       } catch (InterruptedException ignored) {\r
+                       }\r
+               }\r
+\r
+               // A buffer underflow will cause the source to stop.\r
+               if (!isPlaying || alGetSourcei(sourceID, AL_SOURCE_STATE) != AL_PLAYING) {\r
+                       System.out.println("underflow!");\r
+                       alSourcePlay(sourceID);\r
+                       isPlaying = true;\r
+               }\r
+\r
+               return written;\r
+       }\r
+\r
+       public void stop () {\r
+               if (sourceID == -1) return;\r
+               audio.freeSource(sourceID);\r
+               sourceID = -1;\r
+               renderedSeconds = 0;\r
+               isPlaying = false;\r
+       }\r
+\r
+       public boolean isPlaying () {\r
+               if (sourceID == -1) return false;\r
+               return isPlaying;\r
+       }\r
+\r
+       public void setVolume (float volume) {\r
+               this.volume = volume;\r
+               if (sourceID != -1) alSourcef(sourceID, AL_GAIN, volume);\r
+       }\r
+\r
+       public float getPosition () {\r
+               if (sourceID == -1) return 0;\r
+               return renderedSeconds + alGetSourcef(sourceID, AL11.AL_SEC_OFFSET);\r
+       }\r
+\r
+       public int getChannels () {\r
+               return format == AL_FORMAT_STEREO16 ? 2 : 1;\r
+       }\r
+\r
+       public int getRate () {\r
+               return sampleRate;\r
+       }\r
+\r
+       public void dispose () {\r
+               if (buffers == null) return;\r
+               if (sourceID != -1) {\r
+                       audio.freeSource(sourceID);\r
+                       sourceID = -1;\r
+               }\r
+               alDeleteBuffers(buffers);\r
+               buffers = null;\r
+       }\r
+\r
+       public boolean isMono () {\r
+               return false;\r
+       }\r
+\r
+       public int getLatency () {\r
+               return (int)(secondsPerBuffer * bufferCount * 1000);\r
+       }\r
+}\r
index c8684c5..fdf04bb 100644 (file)
@@ -1,47 +1,30 @@
+\r
 package com.badlogic.gdx;\r
 \r
-/**\r
- * Convenience implementation of {@link ApplicationListener}. Derrive from this and only\r
- * override what you need.\r
- * @author mzechner\r
- *\r
- */\r
+/** Convenience implementation of {@link ApplicationListener}. Derrive from this and only override what you need.\r
+ * @author mzechner */\r
 public abstract class ApplicationAdapter implements ApplicationListener {\r
-\r
        @Override\r
        public void create () {\r
-               // TODO Auto-generated method stub\r
-               \r
        }\r
 \r
        @Override\r
        public void resize (int width, int height) {\r
-               // TODO Auto-generated method stub\r
-               \r
        }\r
 \r
        @Override\r
        public void render () {\r
-               // TODO Auto-generated method stub\r
-               \r
        }\r
 \r
        @Override\r
        public void pause () {\r
-               // TODO Auto-generated method stub\r
-               \r
        }\r
 \r
        @Override\r
        public void resume () {\r
-               // TODO Auto-generated method stub\r
-               \r
        }\r
 \r
        @Override\r
        public void dispose () {\r
-               // TODO Auto-generated method stub\r
-               \r
        }\r
-\r
 }\r
index 3f5e6c8..02cfc38 100644 (file)
@@ -378,7 +378,7 @@ public class ShapeRenderer {
 \r
        /** Calls {@link #circle(float, float, float, int)} by estimating the number of segments needed for a smooth circle. */\r
        public void circle (float x, float y, float radius) {\r
-               circle(x, y, radius, (int)(4 * (float)Math.sqrt(radius)));\r
+               circle(x, y, radius, (int)(6 * (float)Math.cbrt(radius)));\r
        }\r
 \r
        public void circle (float x, float y, float radius, int segments) {\r