Add mp3 support

This commit is contained in:
Stephen Seo 2018-10-30 14:11:48 +09:00
parent 3c6c22432e
commit f32d872bbf
4 changed files with 206 additions and 26 deletions

View file

@ -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) 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). 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).

View file

@ -38,6 +38,8 @@ dependencies {
// or you may define them like so.. // or you may define them like so..
//compile "some.group:artifact:version:classifier" //compile "some.group:artifact:version:classifier"
//compile "some.group:artifact:version" //compile "some.group:artifact:version"
// toml parser
compile "net.consensys.cava:cava-toml:0.3.1" compile "net.consensys.cava:cava-toml:0.3.1"
// real examples // real examples
@ -83,6 +85,8 @@ shadowJar {
relocate 'net.consensys.cava', 'shadow.turnbasedmc.net.consensys.cava' relocate 'net.consensys.cava', 'shadow.turnbasedmc.net.consensys.cava'
relocate 'org.antlr.v4', 'shadow.turnbasedmc.org.antlr.v4' relocate 'org.antlr.v4', 'shadow.turnbasedmc.org.antlr.v4'
relocate 'javax.annotation', 'shadow.turnbasedmc.javax.annotation' relocate 'javax.annotation', 'shadow.turnbasedmc.javax.annotation'
relocate 'fr.delthas', 'shadow.turnbasedmc.fr.delthas'
} }
reobf { shadowJar { mappingType = "SEARGE" } } reobf { shadowJar { mappingType = "SEARGE" } }

BIN
libs/javamp3-1.0.3.jar Normal file

Binary file not shown.

View file

@ -1,18 +1,17 @@
package com.seodisparate.TurnBasedMinecraft.client; package com.seodisparate.TurnBasedMinecraft.client;
import java.io.BufferedInputStream; import java.io.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.util.ArrayList; 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.MidiSystem;
import javax.sound.midi.Sequencer; import javax.sound.midi.Sequencer;
import javax.sound.sampled.AudioSystem; import javax.sound.sampled.*;
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import fr.delthas.javamp3.Sound;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import com.seodisparate.TurnBasedMinecraft.common.TurnBasedMinecraftMod; import com.seodisparate.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
@ -31,7 +30,9 @@ public class BattleMusic
private Clip clip; private Clip clip;
private boolean playingIsSilly; private boolean playingIsSilly;
private boolean isPlaying; private boolean isPlaying;
private Thread mp3StreamThread;
private MP3Streamer mp3StreamRunnable;
public BattleMusic(Logger logger) public BattleMusic(Logger logger)
{ {
initialized = false; initialized = false;
@ -39,7 +40,9 @@ public class BattleMusic
battleMusic = new ArrayList<File>(); battleMusic = new ArrayList<File>();
sillyMusic = new ArrayList<File>(); sillyMusic = new ArrayList<File>();
isPlaying = false; isPlaying = false;
mp3StreamThread = null;
mp3StreamRunnable = null;
try { try {
sequencer = MidiSystem.getSequencer(); sequencer = MidiSystem.getSequencer();
sequencer.open(); sequencer.open();
@ -88,14 +91,15 @@ public class BattleMusic
return false; return false;
} }
String ext = name.substring(extIndex + 1).toLowerCase(); 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) for(File f : battleFiles)
{ {
battleMusic.add(f); battleMusic.add(f);
} }
logger.info("Got " + battleMusic.size() + " battle music files");
File[] sillyFiles = sillyMusicFolder.listFiles(new FilenameFilter() { File[] sillyFiles = sillyMusicFolder.listFiles(new FilenameFilter() {
@Override @Override
public boolean accept(File dir, String name) public boolean accept(File dir, String name)
@ -106,14 +110,15 @@ public class BattleMusic
return false; return false;
} }
String ext = name.substring(extIndex + 1).toLowerCase(); 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) for(File f : sillyFiles)
{ {
sillyMusic.add(f); sillyMusic.add(f);
} }
logger.info("Got " + sillyMusic.size() + " battle music files");
initialized = true; initialized = true;
pickNextBattle(); pickNextBattle();
@ -154,7 +159,7 @@ public class BattleMusic
{ {
volume = 1.0f; volume = 1.0f;
} }
play(nextBattle, volume); play(nextBattle, volume, true);
pickNextBattle(); pickNextBattle();
playingIsSilly = false; playingIsSilly = false;
isPlaying = true; isPlaying = true;
@ -170,13 +175,13 @@ public class BattleMusic
{ {
volume = 1.0f; volume = 1.0f;
} }
play(nextSilly, volume); play(nextSilly, volume, false);
pickNextSilly(); pickNextSilly();
playingIsSilly = true; playingIsSilly = true;
isPlaying = true; isPlaying = true;
} }
private void play(File next, float volume) private void play(File next, float volume, boolean isBattleType)
{ {
if(initialized && next != null) if(initialized && next != null)
{ {
@ -187,9 +192,21 @@ public class BattleMusic
String suffix = next.getName().substring(next.getName().length() - 3).toLowerCase(); String suffix = next.getName().substring(next.getName().length() - 3).toLowerCase();
if(suffix.equals("mid")) if(suffix.equals("mid"))
{ {
sequencer.stop(); if(sequencer.isRunning())
clip.stop(); {
clip.close(); 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 { try {
sequencer.setSequence(new BufferedInputStream(new FileInputStream(next))); sequencer.setSequence(new BufferedInputStream(new FileInputStream(next)));
} catch (Throwable t) } catch (Throwable t)
@ -197,7 +214,7 @@ public class BattleMusic
logger.error("Failed to play battle music (midi)"); logger.error("Failed to play battle music (midi)");
return; return;
} }
sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY); sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
sequencer.start(); sequencer.start();
} }
@ -212,22 +229,67 @@ public class BattleMusic
clip.stop(); clip.stop();
clip.close(); clip.close();
} }
if(mp3StreamThread != null && mp3StreamThread.isAlive())
{
mp3StreamRunnable.setKeepPlaying(false);
try { mp3StreamThread.join(); } catch (Throwable t) { /* ignored */ }
}
try try
{ {
clip.open(AudioSystem.getAudioInputStream(next)); clip.open(AudioSystem.getAudioInputStream(next));
} catch(Throwable t) } catch(Throwable t)
{ {
logger.error("Failed to load battle music (wav)"); logger.error("Failed to play battle music (wav)");
return; return;
} }
// set volume // set volume
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
gainControl.setValue(volume * 20.0f - 20.0f); // in decibels gainControl.setValue(volume * 20.0f - 20.0f); // in decibels
clip.loop(Clip.LOOP_CONTINUOUSLY); clip.loop(Clip.LOOP_CONTINUOUSLY);
clip.start(); 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(); sequencer.stop();
clip.stop(); clip.stop();
clip.close(); clip.close();
if(mp3StreamThread != null && mp3StreamThread.isAlive())
{
mp3StreamRunnable.setKeepPlaying(false);
try { mp3StreamThread.join(); } catch (Throwable t) { /* ignored */ }
}
if(resumeMCSounds) if(resumeMCSounds)
{ {
Minecraft.getMinecraft().addScheduledTask(() -> { Minecraft.getMinecraft().addScheduledTask(() -> Minecraft.getMinecraft().getSoundHandler().resumeSounds() );
Minecraft.getMinecraft().getSoundHandler().resumeSounds();
});
} }
isPlaying = false; isPlaying = false;
} }
@ -264,4 +329,112 @@ public class BattleMusic
{ {
return !sillyMusic.isEmpty(); 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();
}
}
}
} }