OSDN Git Service

IOSSound improved: sound FX are played outside the rendering loop for smoother frame...
authorChristoph Aschwanden <contact@noblemaster.com>
Wed, 10 Oct 2012 10:08:42 +0000 (19:08 +0900)
committerChristoph Aschwanden <contact@noblemaster.com>
Wed, 10 Oct 2012 10:08:42 +0000 (19:08 +0900)
backends/gdx-backend-iosmonotouch/mono/mono/libgdx.a
backends/gdx-backend-iosmonotouch/src/com/badlogic/gdx/backends/ios/IOSApplication.java
backends/gdx-backend-iosmonotouch/src/com/badlogic/gdx/backends/ios/IOSGraphics.java
backends/gdx-backend-iosmonotouch/src/com/badlogic/gdx/backends/ios/IOSSound.java

index 77e5da6..362b119 100644 (file)
Binary files a/backends/gdx-backend-iosmonotouch/mono/mono/libgdx.a and b/backends/gdx-backend-iosmonotouch/mono/mono/libgdx.a differ
index 03d74a4..79b1cd3 100644 (file)
@@ -112,7 +112,7 @@ public class IOSApplication extends UIApplicationDelegate implements Application
                uiViewController.set_View(graphics);\r
                this.graphics.Run();\r
                this.uiWindow.MakeKeyAndVisible();\r
-               Gdx.app.log("IOSApplication", "created");\r
+               Gdx.app.debug("IOSApplication", "created");\r
                return true;\r
        }\r
 \r
@@ -141,7 +141,7 @@ public class IOSApplication extends UIApplicationDelegate implements Application
                                width = (int)bounds.get_Width();\r
                           height = (int)bounds.get_Height();\r
                } \r
-               Gdx.app.log("IOSApplication", "View: " + orientation.toString() + " " + width + "x" + height);\r
+               Gdx.app.debug("IOSApplication", "View: " + orientation.toString() + " " + width + "x" + height);\r
                \r
                // return resulting view size (based on orientation)\r
                return new RectangleF(0, 0, width, height);\r
@@ -149,7 +149,7 @@ public class IOSApplication extends UIApplicationDelegate implements Application
        \r
        @Override\r
        public void OnActivated(UIApplication uiApp) {\r
-               Gdx.app.log("IOSApplication", "resumed");\r
+               Gdx.app.debug("IOSApplication", "resumed");\r
                if(!firstResume) {\r
                        graphics.MakeCurrent();\r
                        listener.resume();\r
@@ -159,7 +159,7 @@ public class IOSApplication extends UIApplicationDelegate implements Application
 \r
        @Override\r
        public void OnResignActivation(UIApplication uiApp) {\r
-               Gdx.app.log("IOSApplication", "paused");\r
+               Gdx.app.debug("IOSApplication", "paused");\r
                graphics.MakeCurrent();\r
                listener.pause();\r
                Gdx.gl.glFlush();\r
@@ -167,7 +167,7 @@ public class IOSApplication extends UIApplicationDelegate implements Application
 \r
        @Override\r
        public void WillTerminate(UIApplication uiApp) {\r
-               Gdx.app.log("IOSApplication", "disposed");\r
+               Gdx.app.debug("IOSApplication", "disposed");\r
                graphics.MakeCurrent();\r
                listener.dispose();\r
                Gdx.gl.glFlush();\r
index d7ed378..5b72c5c 100644 (file)
@@ -63,7 +63,7 @@ public class IOSGraphics extends iPhoneOSGameView implements Graphics {
                // setup view and OpenGL
                width = (int)bounds.get_Width();
                height = (int)bounds.get_Height();
-               app.log("IOSGraphics", bounds.get_Width() + "x" + bounds.get_Height() + ", " + UIScreen.get_MainScreen().get_Scale());
+               app.debug("IOSGraphics", bounds.get_Width() + "x" + bounds.get_Height() + ", " + UIScreen.get_MainScreen().get_Scale());
                this.app = app;\r
                this.input = input;
                set_LayerRetainsBacking(false);
@@ -99,7 +99,7 @@ public class IOSGraphics extends iPhoneOSGameView implements Graphics {
                ppiY = ppi;\r
                ppcX = ppiX / 2.54f;\r
                ppcY = ppcY / 2.54f;\r
-               app.log("IOSGraphics", "Display: ppi=" + ppi + ", density=" + density);\r
+               app.debug("IOSGraphics", "Display: ppi=" + ppi + ", density=" + density);\r
                \r
                // time + FPS
                lastFrameTime = System.nanoTime();
@@ -144,8 +144,8 @@ public class IOSGraphics extends iPhoneOSGameView implements Graphics {
        protected void OnResize(EventArgs event) {
                super.OnResize(event);
 \r
-               // noblemaster: I don't think this method will get called on iOS!? (at least not as of 2012-09-27)\r
-               Gdx.app.error("IOSGraphics", "OnResize(...) is not implement.");
+               // not used on iOS\r
+               Gdx.app.debug("IOSGraphics", "iOS OnResize(...) is not implement (don't think it is needed?).");
        }
 
        @ExportAttribute.Annotation("layerClass")
index 28fb1f2..493e46a 100644 (file)
@@ -38,11 +38,63 @@ import com.badlogic.gdx.utils.GdxRuntimeException;
 public class IOSSound implements Sound {
 \r
        /** The maximum number of players to instantiate to support simultaneous playback. Bigger? */\r
-       private static final int MAX_PLAYERS = 10;\r
+       private static final int MAX_PLAYERS = 8;\r
        \r
        /** Our sound players. More than one to support simultaneous playback. */\r
        private AVAudioPlayer[] players;\r
-\r
+       /** The next player we think should be available for play - we circling through them to find a free one. */\r
+       private int playerIndex;\r
+       \r
+       // one single thread will play sounds outside the rendering low (otherwise our FPS drops!)\r
+       private static class PlayThread extends Thread {\r
+               @Override\r
+               public void run () {\r
+                       Gdx.app.debug("IOSSound", "Sound player is running.");\r
+                       \r
+                       // get the latest play thread\r
+                       Thread playThread;\r
+                       synchronized (IOSSound.sync) {\r
+                               playThread = IOSSound.playThread;\r
+                       }\r
+                       \r
+                       // our temp player list\r
+                       List<AVAudioPlayer> playQueueCopy = new ArrayList<AVAudioPlayer>(64);\r
+                       \r
+                       // our play loop which will continue as long as we are the active thread\r
+                       Thread currentThread = Thread.currentThread();\r
+                       while (currentThread == playThread) {\r
+                               // play songs queued via our own copy to not impact rendering performance\r
+                               synchronized (IOSSound.sync) {\r
+                                       playQueueCopy.addAll(playQueue);\r
+                                       playQueue.clear();\r
+                               }\r
+                               for (int i = 0; i < playQueueCopy.size(); i++) {\r
+                                       playQueueCopy.get(i).Play();\r
+                               }\r
+                               playQueueCopy.clear();\r
+                               \r
+                               // sleep \r
+                               try {\r
+                                       Thread.sleep(5);\r
+                               }\r
+                               catch (InterruptedException e) {\r
+                                       Gdx.app.error("IOSSound", "Error in sound player thread.", e);\r
+                               }\r
+                               \r
+                               // get the latest play thread\r
+                               synchronized (IOSSound.sync) {\r
+                                       playThread = IOSSound.playThread;\r
+                               }\r
+                       }\r
+                       \r
+                       Gdx.app.debug("IOSSound", "Sound player is disposed.");\r
+               }               \r
+       }\r
+       private static final Object sync = new Object();\r
+       private static PlayThread playThread = null;\r
+       private static int soundCounter = 0;\r
+       private static List<AVAudioPlayer> playQueue = new ArrayList<AVAudioPlayer>(64);\r
+       \r
        \r
        /**\r
         * Creates a new sound object. We are creating several AVAudioPlayer objects to\r
@@ -65,6 +117,19 @@ public class IOSSound implements Sound {
                                throw new GdxRuntimeException("Error creating audio player (index: " + i + "): " + error[0].ToString());\r
                        }\r
                }\r
+               playerIndex = 0;\r
+               \r
+               // create the play thread if it doesn't exist yet\r
+               synchronized (sync) {\r
+                       soundCounter++;\r
+                       \r
+                       // create play thread as needed: plays sounds outside the rendering loop (smoother rendering)\r
+                       if (playThread == null) {\r
+                               playThread = new PlayThread();\r
+                               playThread.setPriority(Thread.MIN_PRIORITY);\r
+                               playThread.start();\r
+                       }\r
+               }\r
        }\r
 \r
        /**\r
@@ -74,7 +139,12 @@ public class IOSSound implements Sound {
         */\r
        private int findAvailablePlayer() {\r
                for (int i = 0; i < players.length; i++) {\r
-                       if (!players[i].get_Playing()) {\r
+                       int index = (playerIndex + i) % players.length;\r
+                       if (!players[index].get_Playing()) {\r
+                               // point to the next likely free player\r
+                               playerIndex = (index + 1) % players.length; \r
+                               \r
+                               // return the free player\r
                                return i;\r
                        }\r
                }\r
@@ -111,7 +181,11 @@ public class IOSSound implements Sound {
                        player.set_NumberOfLoops(looping ? -1 : 0);  // Note: -1 for looping!\r
                        player.set_Volume(volume);\r
                        player.set_Pan(pan);\r
-                       player.Play();\r
+                       \r
+                       // we let the thread play our song as not to impact rendering performance (FPS)\r
+                       synchronized (sync) {\r
+                               playQueue.add(player);\r
+                       }\r
                }\r
                \r
                // and return the index/id of the player\r
@@ -135,20 +209,35 @@ public class IOSSound implements Sound {
 
        @Override
        public void stop() {
+               synchronized (sync) {\r
+                       // we clear the player queue so no song is player after call to stop!\r
+                       playQueue.clear();\r
+               }\r
+               \r
                // stop all players\r
                for (int i = 0; i < players.length; i++) {\r
                        players[i].Stop();\r
                }\r
        }
-
-       @Override
+\r
+       @Override\r
        public void dispose() {\r
                // dispose all players\r
-               for (int i = 0; i < players.length; i++) {
+               for (int i = 0; i < players.length; i++) {\r
                        players[i].Dispose();\r
                        players[i] = null;\r
-               }
-       }
+               }\r
+               \r
+               // dispose play thread if no more sounds are available\r
+               synchronized (sync) {\r
+                       soundCounter--;\r
+                       \r
+                       // no more sounds?\r
+                       if (soundCounter == 0) {\r
+                               playThread = null;\r
+                       }\r
+               }\r
+       }\r
 
        @Override
        public void stop(long soundId) {\r