]> git.seodisparate.com - TurnBasedMinecraftMod/commitdiff
Add mp3 support
authorStephen Seo <seo.disparate@gmail.com>
Tue, 30 Oct 2018 05:11:48 +0000 (14:11 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Tue, 30 Oct 2018 05:11:48 +0000 (14:11 +0900)
README.md
build.gradle
libs/javamp3-1.0.3.jar [new file with mode: 0644]
src/main/java/com/seodisparate/TurnBasedMinecraft/client/BattleMusic.java

index 03617805ea4998785458ef62ee3ff8f80d8de42e..effefc5a67d7926dde79618a9c9bb5aa3c88f82a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -58,3 +58,6 @@ licenced under the [Apache License 2.0](https://github.com/johnrengelman/shadow/
 
 This mod also uses [Cava-Toml](https://github.com/ConsenSys/cava/tree/master/toml)
 which is licenced under the [Apache License 2.0](https://github.com/ConsenSys/cava/blob/master/LICENSE).
+
+This mod also uses [JavaMP3](https://github.com/kevinstadler/JavaMP3)
+which is licensed under the [MIT License](https://github.com/kevinstadler/JavaMP3/blob/master/LICENSE).
index a8be03dfd8626cd321dd917ab4f24da502f6cb16..df6ff4395343877f28fb4ad429905c097cda9c9a 100644 (file)
@@ -38,6 +38,8 @@ dependencies {
     // or you may define them like so..\r
     //compile "some.group:artifact:version:classifier"\r
     //compile "some.group:artifact:version"\r
+\r
+       // toml parser\r
     compile "net.consensys.cava:cava-toml:0.3.1"\r
       \r
     // real examples\r
@@ -83,6 +85,8 @@ shadowJar {
        relocate 'net.consensys.cava', 'shadow.turnbasedmc.net.consensys.cava'\r
        relocate 'org.antlr.v4', 'shadow.turnbasedmc.org.antlr.v4'\r
        relocate 'javax.annotation', 'shadow.turnbasedmc.javax.annotation'\r
+\r
+       relocate 'fr.delthas', 'shadow.turnbasedmc.fr.delthas'\r
 }\r
 \r
 reobf { shadowJar { mappingType = "SEARGE" } }\r
diff --git a/libs/javamp3-1.0.3.jar b/libs/javamp3-1.0.3.jar
new file mode 100644 (file)
index 0000000..1ce61ed
Binary files /dev/null and b/libs/javamp3-1.0.3.jar differ
index dd784f50f7f0ccff3d1f3bd04b3288b93daa446b..a021495b203547475c736be32f6307b96bd554aa 100644 (file)
@@ -1,18 +1,17 @@
 package com.seodisparate.TurnBasedMinecraft.client;
 
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FilenameFilter;
+import java.io.*;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.sound.midi.MidiSystem;
 import javax.sound.midi.Sequencer;
-import javax.sound.sampled.AudioSystem;
-import javax.sound.sampled.Clip;
-import javax.sound.sampled.FloatControl;
-import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.*;
 
+import fr.delthas.javamp3.Sound;
 import org.apache.logging.log4j.Logger;
 
 import com.seodisparate.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
@@ -31,7 +30,9 @@ public class BattleMusic
     private Clip clip;
     private boolean playingIsSilly;
     private boolean isPlaying;
-    
+    private Thread mp3StreamThread;
+    private MP3Streamer mp3StreamRunnable;
+
     public BattleMusic(Logger logger)
     {
         initialized = false;
@@ -39,7 +40,9 @@ public class BattleMusic
         battleMusic = new ArrayList<File>();
         sillyMusic = new ArrayList<File>();
         isPlaying = false;
-        
+        mp3StreamThread = null;
+        mp3StreamRunnable = null;
+
         try {
             sequencer = MidiSystem.getSequencer();
             sequencer.open();
@@ -88,14 +91,15 @@ public class BattleMusic
                     return false;
                 }
                 String ext = name.substring(extIndex + 1).toLowerCase();
-                return ext.equals("mid") || ext.equals("wav");
+                return ext.equals("mid") || ext.equals("wav") || ext.equals("mp3");
             }
         });
         for(File f : battleFiles)
         {
             battleMusic.add(f);
         }
-        
+        logger.info("Got " + battleMusic.size() + " battle music files");
+
         File[] sillyFiles = sillyMusicFolder.listFiles(new FilenameFilter() {
             @Override
             public boolean accept(File dir, String name)
@@ -106,14 +110,15 @@ public class BattleMusic
                     return false;
                 }
                 String ext = name.substring(extIndex + 1).toLowerCase();
-                return ext.equals("mid") || ext.equals("wav");
+                return ext.equals("mid") || ext.equals("wav") || ext.equals("mp3");
             }
         });
         for(File f : sillyFiles)
         {
             sillyMusic.add(f);
         }
-        
+        logger.info("Got " + sillyMusic.size() + " battle music files");
+
         initialized = true;
         
         pickNextBattle();
@@ -154,7 +159,7 @@ public class BattleMusic
         {
             volume = 1.0f;
         }
-        play(nextBattle, volume);
+        play(nextBattle, volume, true);
         pickNextBattle();
         playingIsSilly = false;
         isPlaying = true;
@@ -170,13 +175,13 @@ public class BattleMusic
         {
             volume = 1.0f;
         }
-        play(nextSilly, volume);
+        play(nextSilly, volume, false);
         pickNextSilly();
         playingIsSilly = true;
         isPlaying = true;
     }
     
-    private void play(File next, float volume)
+    private void play(File next, float volume, boolean isBattleType)
     {
         if(initialized && next != null)
         {
@@ -187,9 +192,21 @@ public class BattleMusic
             String suffix = next.getName().substring(next.getName().length() - 3).toLowerCase();
             if(suffix.equals("mid"))
             {
-                sequencer.stop();
-                clip.stop();
-                clip.close();
+                if(sequencer.isRunning())
+                {
+                    sequencer.stop();
+                }
+                if(clip.isActive())
+                {
+                    clip.stop();
+                    clip.close();
+                }
+                if(mp3StreamThread != null && mp3StreamThread.isAlive())
+                {
+                    mp3StreamRunnable.setKeepPlaying(false);
+                    try { mp3StreamThread.join(); } catch (Throwable t) { /* ignored */ }
+                }
+
                 try {
                     sequencer.setSequence(new BufferedInputStream(new FileInputStream(next)));
                 } catch (Throwable t)
@@ -197,7 +214,7 @@ public class BattleMusic
                     logger.error("Failed to play battle music (midi)");
                     return;
                 }
-                
+
                 sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
                 sequencer.start();
             }
@@ -212,22 +229,67 @@ public class BattleMusic
                     clip.stop();
                     clip.close();
                 }
+                if(mp3StreamThread != null && mp3StreamThread.isAlive())
+                {
+                    mp3StreamRunnable.setKeepPlaying(false);
+                    try { mp3StreamThread.join(); } catch (Throwable t) { /* ignored */ }
+                }
+
                 try
                 {
                     clip.open(AudioSystem.getAudioInputStream(next));
                 } catch(Throwable t)
                 {
-                    logger.error("Failed to load battle music (wav)");
+                    logger.error("Failed to play battle music (wav)");
                     return;
                 }
                 
                 // set volume
                 FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
                 gainControl.setValue(volume * 20.0f - 20.0f); // in decibels
-                
+
                 clip.loop(Clip.LOOP_CONTINUOUSLY);
                 clip.start();
             }
+            else if(suffix.equals("mp3"))
+            {
+                if(sequencer.isRunning())
+                {
+                    sequencer.stop();
+                }
+                if(clip.isActive())
+                {
+                    clip.stop();
+                    clip.close();
+                }
+                if(mp3StreamThread != null && mp3StreamThread.isAlive())
+                {
+                    mp3StreamRunnable.setKeepPlaying(false);
+                    try { mp3StreamThread.join(); } catch (Throwable t) { /* ignored */ }
+                }
+
+                try
+                {
+                    if(mp3StreamRunnable == null)
+                    {
+                        mp3StreamRunnable = new MP3Streamer(next, logger, volume);
+                    }
+                    else
+                    {
+                        mp3StreamRunnable.setMp3File(next);
+                        mp3StreamRunnable.setVolume(volume);
+                    }
+                    mp3StreamThread = new Thread(mp3StreamRunnable);
+                    mp3StreamThread.start();
+
+                    logger.info("Started playing mp3 " + next.getName());
+                }
+                catch (Throwable t)
+                {
+                    logger.error("Failed to play battle music (mp3)");
+                    return;
+                }
+            }
         }
     }
     
@@ -236,11 +298,14 @@ public class BattleMusic
         sequencer.stop();
         clip.stop();
         clip.close();
+        if(mp3StreamThread != null && mp3StreamThread.isAlive())
+        {
+            mp3StreamRunnable.setKeepPlaying(false);
+            try { mp3StreamThread.join(); } catch (Throwable t) { /* ignored */ }
+        }
         if(resumeMCSounds)
         {
-            Minecraft.getMinecraft().addScheduledTask(() -> {
-                Minecraft.getMinecraft().getSoundHandler().resumeSounds();
-            });
+            Minecraft.getMinecraft().addScheduledTask(() -> Minecraft.getMinecraft().getSoundHandler().resumeSounds() );
         }
         isPlaying = false;
     }
@@ -264,4 +329,112 @@ public class BattleMusic
     {
         return !sillyMusic.isEmpty();
     }
+
+    private class MP3Streamer implements Runnable
+    {
+        private AtomicBoolean keepPlaying;
+        private File mp3File;
+        private Logger logger;
+        private float volume;
+
+        public MP3Streamer(File mp3File, Logger logger, float volume)
+        {
+            keepPlaying = new AtomicBoolean(true);
+            this.mp3File = mp3File;
+            this.logger = logger;
+            this.volume = volume;
+            if(this.volume > 1.0f)
+            {
+                this.volume = 1.0f;
+            }
+            else if(this.volume < 0.0f)
+            {
+                this.volume = 0.0f;
+            }
+        }
+
+        public void setKeepPlaying(boolean playing)
+        {
+            keepPlaying.set(playing);
+        }
+
+        public void setMp3File(File mp3File)
+        {
+            this.mp3File = mp3File;
+        }
+
+        public void setVolume(float volume)
+        {
+            this.volume = volume;
+        }
+
+        @Override
+        public void run()
+        {
+            keepPlaying.set(true);
+            SourceDataLine sdl = null;
+            try
+            {
+                Sound mp3Sound = new Sound(new FileInputStream(mp3File));
+                AudioFormat audioFormat = mp3Sound.getAudioFormat();
+                sdl = AudioSystem.getSourceDataLine(audioFormat);
+                sdl.open(audioFormat);
+                {
+                    FloatControl volumeControl = (FloatControl) sdl.getControl(FloatControl.Type.MASTER_GAIN);
+                    volumeControl.setValue(volume * 20.0f - 20.0f); // in decibels
+                }
+
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                byte[] cached = null;
+                int cachedOffset = 0;
+                int cachedSize = 0;
+                byte[] buf = new byte[4096];
+                sdl.start();
+                int read = mp3Sound.read(buf, 0, 4096);
+                while(keepPlaying.get())
+                {
+                    if(baos != null)
+                    {
+                        if(read != -1)
+                        {
+                            sdl.write(buf, 0, read);
+                            baos.write(buf, 0, read);
+                            read = mp3Sound.read(buf, 0, 4096);
+                        }
+                        else
+                        {
+                            mp3Sound.close();
+                            mp3Sound = null;
+                            cached = baos.toByteArray();
+                            baos = null;
+                        }
+                    }
+                    else
+                    {
+                        cachedSize = cached.length - cachedOffset;
+                        if(cachedSize > 4096)
+                        {
+                            cachedSize = 4096;
+                        }
+                        sdl.write(cached, cachedOffset, cachedSize);
+                        cachedOffset += cachedSize;
+                        if(cachedOffset >= cached.length)
+                        {
+                            cachedOffset = 0;
+                        }
+                    }
+                }
+            }
+            catch (Throwable t)
+            {
+                logger.error("Stream play mp3", t);
+            }
+            if(sdl != null)
+            {
+                sdl.stop();
+                sdl.flush();
+                sdl.close();
+            }
+        }
+    }
 }