OSDN Git Service

[added] Music getPsoition.
authornathan.sweet <nathan.sweet@6c4fd544-2939-11df-bb46-9574ba5d0bfa>
Wed, 23 Feb 2011 06:42:04 +0000 (06:42 +0000)
committernathan.sweet <nathan.sweet@6c4fd544-2939-11df-bb46-9574ba5d0bfa>
Wed, 23 Feb 2011 06:42:04 +0000 (06:42 +0000)
[added] Sound stop.
[fixed] Music stopping on buffer underflow.
[fixed] How music/sound obtains IDs so they can't stomp each other (sound just lets the stream stop in its own, music explicitly stops it).

backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidMusic.java
backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/AndroidSound.java
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleMusic.java
backends/gdx-backends-angle/src/com/badlogic/gdx/backends/angle/AngleSound.java
backends/gdx-openal/src/com/badlogic/gdx/backends/openal/OpenALAudio.java
backends/gdx-openal/src/com/badlogic/gdx/backends/openal/OpenALMusic.java
backends/gdx-openal/src/com/badlogic/gdx/backends/openal/OpenALSound.java
gdx/src/com/badlogic/gdx/audio/Music.java
gdx/src/com/badlogic/gdx/audio/Sound.java
tests/gdx-tests/src/com/badlogic/gdx/tests/SoundTest.java

index d274f47..1095e53 100644 (file)
@@ -73,4 +73,7 @@ public class AndroidMusic implements Music {
                isPrepared = false;\r
        }\r
 \r
+       public float getPosition () {\r
+               return player.getCurrentPosition() * 1000;\r
+       }\r
 }\r
index 86ad9a2..7ad3f2e 100644 (file)
@@ -42,4 +42,7 @@ final class AndroidSound implements Sound {
                soundPool.play(soundId, volume, volume, 1, 0, 1);\r
        }\r
 \r
+       public void stop () {\r
+               soundPool.stop(soundId);\r
+       }\r
 }\r
index c625dc6..010103a 100644 (file)
@@ -167,4 +167,8 @@ final class AngleMusic implements Music, Runnable {
                        }\r
                }\r
        }\r
+\r
+       public float getPosition () {\r
+               throw new UnsupportedOperationException("Upgrade Angle to OpenAL.");\r
+       }\r
 }\r
index fd88383..d6d3a54 100644 (file)
@@ -142,6 +142,10 @@ final class AngleSound implements Sound {
                audio.enqueueSound(this, volume);\r
        }\r
 \r
+       public void stop () {\r
+               throw new UnsupportedOperationException("Upgrade Angle to OpenAL.");\r
+       }\r
+\r
        /**\r
         * @return the {@link AudioFormat} of the audio data\r
         */\r
@@ -155,5 +159,4 @@ final class AngleSound implements Sound {
        public float[] getAudioData () {\r
                return samples;\r
        }\r
-\r
 }\r
index 37f214c..681f6f2 100644 (file)
@@ -27,6 +27,7 @@ import com.badlogic.gdx.utils.Array;
 import com.badlogic.gdx.utils.GdxRuntimeException;\r
 import com.badlogic.gdx.utils.IntArray;\r
 import com.badlogic.gdx.utils.ObjectMap;\r
+import com.badlogic.gdx.utils.Pool;\r
 \r
 import static org.lwjgl.openal.AL10.*;\r
 \r
@@ -34,7 +35,7 @@ import static org.lwjgl.openal.AL10.*;
  * @author Nathan Sweet\r
  */\r
 public class OpenALAudio implements Audio {\r
-       private int[] streams;\r
+       private IntArray idleStreams, allStreams;\r
        private ObjectMap<String, Class<? extends OpenALSound>> extensionToSoundClass = new ObjectMap();\r
        private ObjectMap<String, Class<? extends OpenALMusic>> extensionToMusicClass = new ObjectMap();\r
 \r
@@ -58,13 +59,13 @@ public class OpenALAudio implements Audio {
                        throw new GdxRuntimeException("Error initializing OpenAL.", ex);\r
                }\r
 \r
-               IntArray streams = new IntArray(false, simultaneousStreams);\r
+               allStreams = new IntArray(false, simultaneousStreams);\r
                for (int i = 0; i < simultaneousStreams; i++) {\r
                        int streamID = alGenSources();\r
                        if (alGetError() != AL_NO_ERROR) break;\r
-                       streams.add(streamID);\r
+                       allStreams.add(streamID);\r
                }\r
-               this.streams = streams.items;\r
+               idleStreams = new IntArray(allStreams);\r
 \r
                FloatBuffer orientation = (FloatBuffer)BufferUtils.createFloatBuffer(6)\r
                        .put(new float[] {0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f}).flip();\r
@@ -109,23 +110,30 @@ public class OpenALAudio implements Audio {
                }\r
        }\r
 \r
-       int getIdleStreamID () {\r
-               for (int i = 0, n = streams.length; i < n; i++) {\r
-                       int streamID = streams[i];\r
+       int obtainStream (boolean isMusic) {\r
+               for (int i = 0, n = idleStreams.size; i < n; i++) {\r
+                       int streamID = idleStreams.get(i);\r
                        int state = alGetSourcei(streamID, AL_SOURCE_STATE);\r
-                       if (state != AL_PLAYING && state != AL_PAUSED) return streamID;\r
+                       if (state != AL_PLAYING && state != AL_PAUSED) {\r
+                               if (isMusic) idleStreams.removeIndex(i);\r
+                               return streamID;\r
+                       }\r
                }\r
                return -1;\r
        }\r
 \r
+       void freeStream (int streamID) {\r
+               idleStreams.add(streamID);\r
+       }\r
+\r
        public void update () {\r
                for (int i = 0; i < music.size; i++)\r
                        music.items[i].update();\r
        }\r
 \r
        public void dispose () {\r
-               for (int i = 0, n = streams.length; i < n; i++) {\r
-                       int streamID = streams[i];\r
+               for (int i = 0, n = allStreams.size; i < n; i++) {\r
+                       int streamID = allStreams.get(i);\r
                        int state = alGetSourcei(streamID, AL_SOURCE_STATE);\r
                        if (state != AL_STOPPED) alSourceStop(streamID);\r
                        alDeleteSources(streamID);\r
index f6194b2..1c5f842 100644 (file)
@@ -17,6 +17,7 @@ import java.nio.ByteBuffer;
 import java.nio.IntBuffer;\r
 \r
 import org.lwjgl.BufferUtils;\r
+import org.lwjgl.openal.AL11;\r
 \r
 import com.badlogic.gdx.audio.Music;\r
 import com.badlogic.gdx.files.FileHandle;\r
@@ -30,6 +31,7 @@ import static org.lwjgl.openal.AL10.*;
 public abstract class OpenALMusic implements Music {\r
        static private final int bufferSize = 4096 * 10;\r
        static private final int bufferCount = 3;\r
+       static private final int bytesPerSample = 2;\r
        static private final byte[] tempBytes = new byte[bufferSize];\r
        static private final ByteBuffer tempBuffer = BufferUtils.createByteBuffer(bufferSize);\r
 \r
@@ -37,8 +39,9 @@ public abstract class OpenALMusic implements Music {
        private IntBuffer buffers;\r
        private int streamID = -1;\r
        private int format, sampleRate;\r
-       private boolean isLooping;\r
+       private boolean isLooping, isPlaying;\r
        private float volume = 1;\r
+       private float renderedSeconds, secondsPerBuffer;\r
 \r
        protected final FileHandle file;\r
 \r
@@ -56,19 +59,27 @@ public abstract class OpenALMusic implements Music {
        protected void setup (int channels, int sampleRate) {\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 play () {\r
                if (streamID == -1) {\r
-                       streamID = audio.getIdleStreamID();\r
+                       streamID = audio.obtainStream(true);\r
                        if (streamID == -1) return;\r
+                       alSourceStop(streamID);\r
+                       alSourcei(streamID, AL_BUFFER, 0);\r
                        alSourcei(streamID, AL_LOOPING, AL_FALSE);\r
                        alSourcef(streamID, AL_GAIN, volume);\r
                        for (int i = 0; i < bufferCount; i++)\r
                                fill(buffers.get(i));\r
                        alSourceQueueBuffers(streamID, buffers);\r
+                       if (alGetError() != AL_NO_ERROR) {\r
+                               stop();\r
+                               return;\r
+                       }\r
                }\r
                alSourcePlay(streamID);\r
+               isPlaying = true;\r
        }\r
 \r
        public void stop () {\r
@@ -76,16 +87,20 @@ public abstract class OpenALMusic implements Music {
                reset();\r
                alSourceStop(streamID);\r
                alSourcei(streamID, AL_BUFFER, 0);\r
+               audio.freeStream(streamID);\r
                streamID = -1;\r
+               renderedSeconds = 0;\r
+               isPlaying = false;\r
        }\r
 \r
        public void pause () {\r
                if (streamID != -1) alSourcePause(streamID);\r
+               isPlaying = false;\r
        }\r
 \r
        public boolean isPlaying () {\r
                if (streamID == -1) return false;\r
-               return alGetSourcei(streamID, AL_SOURCE_STATE) == AL_PLAYING;\r
+               return isPlaying;\r
        }\r
 \r
        public void setLooping (boolean isLooping) {\r
@@ -101,6 +116,11 @@ public abstract class OpenALMusic implements Music {
                if (streamID != -1) alSourcef(streamID, AL_GAIN, volume);\r
        }\r
 \r
+       public float getPosition () {\r
+               if (streamID == -1) return 0;\r
+               return renderedSeconds + alGetSourcef(streamID, AL11.AL_SEC_OFFSET);\r
+       }\r
+\r
        /**\r
         * Fills as much of the buffer as possible and returns the number of bytes filled. Returns <= 0 to indicate the end of the\r
         * stream.\r
@@ -114,10 +134,13 @@ public abstract class OpenALMusic implements Music {
 \r
        public void update () {\r
                if (streamID == -1) return;\r
+               // A buffer underflow will cause the source to stop.\r
+               if (isPlaying && alGetSourcei(streamID, AL_SOURCE_STATE) != AL_PLAYING) alSourcePlay(streamID);\r
                int buffers = alGetSourcei(streamID, AL_BUFFERS_PROCESSED);\r
                while (buffers-- > 0) {\r
                        int bufferID = alSourceUnqueueBuffers(streamID);\r
                        if (bufferID == AL_INVALID_VALUE) break;\r
+                       renderedSeconds += secondsPerBuffer;\r
                        if (!fill(bufferID)) return;\r
                        alSourceQueueBuffers(streamID, bufferID);\r
                }\r
@@ -129,10 +152,13 @@ public abstract class OpenALMusic implements Music {
                if (length <= 0) {\r
                        if (isLooping) {\r
                                reset();\r
+                               renderedSeconds = 0;\r
                                length = read(tempBytes);\r
                                if (length <= 0) return false;\r
-                       } else\r
+                       } else {\r
+                               stop();\r
                                return false;\r
+                       }\r
                }\r
                tempBuffer.put(tempBytes, 0, length).flip();\r
                alBufferData(bufferID, format, tempBuffer, sampleRate);\r
@@ -146,6 +172,7 @@ public abstract class OpenALMusic implements Music {
                        audio.music.removeValue(this, true);\r
                        alSourceStop(streamID);\r
                        alSourcei(streamID, AL_BUFFER, 0);\r
+                       audio.freeStream(streamID);\r
                        streamID = -1;\r
                }\r
                alDeleteBuffers(buffers);\r
index fa3510b..f90fee5 100644 (file)
@@ -16,6 +16,8 @@ package com.badlogic.gdx.backends.openal;
 import java.nio.ByteBuffer;\r
 import java.nio.ByteOrder;\r
 \r
+import org.lwjgl.openal.AL11;\r
+\r
 import com.badlogic.gdx.audio.Sound;\r
 \r
 import static org.lwjgl.openal.AL10.*;\r
@@ -50,9 +52,10 @@ public class OpenALSound implements Sound {
        }\r
 \r
        public void play (float volume) {\r
-               streamID = audio.getIdleStreamID();\r
+               streamID = audio.obtainStream(false);\r
                if (streamID == -1) return;\r
                alSourceStop(streamID);\r
+               alSourcei(streamID, AL_BUFFER, 0);\r
                alSourcei(streamID, AL_BUFFER, bufferID);\r
                alSourcei(streamID, AL_LOOPING, AL_FALSE);\r
                alSourcef(streamID, AL_GAIN, volume);\r
@@ -60,16 +63,20 @@ public class OpenALSound implements Sound {
        }\r
 \r
        public void loop () {\r
-               streamID = audio.getIdleStreamID();\r
+               streamID = audio.obtainStream(false);\r
                if (streamID == -1) return;\r
                alSourceStop(streamID);\r
+               alSourcei(streamID, AL_BUFFER, 0);\r
                alSourcei(streamID, AL_BUFFER, bufferID);\r
                alSourcei(streamID, AL_LOOPING, AL_TRUE);\r
                alSourcePlay(streamID);\r
        }\r
 \r
        public void stop () {\r
-               if (streamID != -1) alSourceStop(streamID);\r
+               if (streamID == -1) return;\r
+               alSourceStop(streamID);\r
+               alSourcei(streamID, AL_BUFFER, 0);\r
+               streamID = -1;\r
        }\r
 \r
        public void dispose () {\r
index c5799cc..69b03f2 100644 (file)
@@ -56,19 +56,19 @@ public interface Music extends Disposable {
        public void stop ();\r
 \r
        /**\r
-        * @return whether this music stream is playing or not\r
+        * @return whether this music stream is playing\r
         */\r
        public boolean isPlaying ();\r
 \r
        /**\r
-        * Sets whether the music stream is looping or not. This can be called at any time, whether the stream is playing or not.\r
+        * Sets whether the music stream is looping. This can be called at any time, whether the stream is playing.\r
         * \r
-        * @param isLooping whether to loop the stream or not\r
+        * @param isLooping whether to loop the stream\r
         */\r
        public void setLooping (boolean isLooping);\r
 \r
        /**\r
-        * @return whether the music stream is playing or not.\r
+        * @return whether the music stream is playing.\r
         */\r
        public boolean isLooping ();\r
 \r
@@ -81,6 +81,11 @@ public interface Music extends Disposable {
        public void setVolume (float volume);\r
 \r
        /**\r
+        * Returns the playback position in milliseconds.\r
+        */\r
+       public float getPosition ();\r
+\r
+       /**\r
         * Needs to be called when the Music is no longer needed.\r
         */\r
        public void dispose ();\r
index ad90b5c..04f9ebc 100644 (file)
@@ -32,18 +32,22 @@ import com.badlogic.gdx.utils.Disposable;
  */\r
 public interface Sound extends Disposable {\r
        /**\r
-        * Plays the sound, you can call this repeatedly to play the same sound a couple of times with a bit of lag introduced.\r
+        * Plays the sound. If the sound is already playing, it will be played again, concurrently.\r
         */\r
        public void play ();\r
 \r
        /**\r
-        * Plays the sound, you can call this repeatedly to play the same sound a couple of times with a bit of lag introduced.\r
-        * \r
+        * Plays the sound. If the sound is already playing, it will be played again, concurrently.\r
         * @param volume the volume in the range [0,1]\r
         */\r
        public void play (float volume);\r
 \r
        /**\r
+        * Stops the sound.\r
+        */\r
+       public void stop ();\r
+\r
+       /**\r
         * Releases all the resources.\r
         */\r
        public void dispose ();\r
index e8ed819..a8db616 100644 (file)
@@ -15,9 +15,13 @@ package com.badlogic.gdx.tests;
 \r
 import com.badlogic.gdx.Files.FileType;\r
 import com.badlogic.gdx.Gdx;\r
+import com.badlogic.gdx.Input;\r
 import com.badlogic.gdx.InputProcessor;\r
 import com.badlogic.gdx.audio.Music;\r
 import com.badlogic.gdx.audio.Sound;\r
+import com.badlogic.gdx.graphics.GL10;\r
+import com.badlogic.gdx.graphics.g2d.BitmapFont;\r
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;\r
 import com.badlogic.gdx.tests.utils.GdxTest;\r
 \r
 public class SoundTest extends GdxTest implements InputProcessor {\r
@@ -25,19 +29,29 @@ public class SoundTest extends GdxTest implements InputProcessor {
        Music music;\r
        float volume = 0.5f;\r
 \r
+       BitmapFont font;\r
+       SpriteBatch batch;\r
+\r
        @Override public void render () {\r
+               Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);\r
+               batch.begin();\r
+               font.draw(batch, "Position: " + music.getPosition(), 30, 146);\r
+               batch.end();\r
        }\r
 \r
        @Override public void create () {\r
-//             sound = Gdx.audio.newSound(Gdx.files.getFileHandle("data/shotgun.wav", FileType.Internal));\r
+               // sound = Gdx.audio.newSound(Gdx.files.getFileHandle("data/shotgun.wav", FileType.Internal));\r
                sound = Gdx.audio.newSound(Gdx.files.getFileHandle("data/sell_buy_item.wav", FileType.Internal));\r
 \r
-//             music = Gdx.audio.newMusic(Gdx.files.internal("data/cloudconnected.ogg"));\r
+               // music = Gdx.audio.newMusic(Gdx.files.internal("data/cloudconnected.ogg"));\r
                music = Gdx.audio.newMusic(Gdx.files.getFileHandle("data/threeofaperfectpair.mp3", FileType.Internal));\r
                music.setVolume(volume);\r
                music.play();\r
                music.setLooping(true);\r
                Gdx.input.setInputProcessor(this);\r
+\r
+               batch = new SpriteBatch();\r
+               font = new BitmapFont(Gdx.files.internal("data/verdana39.fnt"), Gdx.files.internal("data/verdana39.png"), false);\r
        }\r
 \r
        @Override public boolean keyDown (int keycode) {\r
@@ -53,12 +67,20 @@ public class SoundTest extends GdxTest implements InputProcessor {
        }\r
 \r
        @Override public boolean keyUp (int keycode) {\r
-\r
+               if (keycode != Input.Keys.KEYCODE_SPACE) return false;\r
+               if (music.isPlaying())\r
+                       music.pause();\r
+               else\r
+                       music.play();\r
                return false;\r
        }\r
 \r
        @Override public boolean touchDown (int x, int y, int pointer, int newParam) {\r
                sound.play(1f);\r
+               if (music.isPlaying())\r
+                       music.stop();\r
+               else\r
+                       music.play();\r
                return false;\r
        }\r
 \r