From d32794152d4d1d43a25724f9c0688e3252777c6f Mon Sep 17 00:00:00 2001 From: Recrown Date: Sat, 12 Aug 2017 00:52:59 -0500 Subject: [PATCH] initial attempt at implementing mp3 --- build.gradle | 7 +- .../rhythmbullet/audio/AudioAnalyzer.java | 6 +- .../zero1hd/rhythmbullet/audio/AudioData.java | 14 +- .../rhythmbullet/audio/Mp3AudioData.java | 129 ++++++------------ .../rhythmbullet/audio/WavAudioData.java | 10 +- .../audio/map/RhythmMapAlgorithm.java | 7 - .../zero1hd/rhythmbullet/entity/Entity.java | 1 + .../rhythmbullet/entity/enemies/Flake.java | 4 +- .../rhythmbullet/entity/enemies/Shard.java | 2 + .../rhythmbullet/screens/CreativeScreen.java | 2 +- .../rhythmbullet/screens/GameScreen.java | 2 +- .../rhythmbullet/ui/stages/GameHUD.java | 18 ++- .../ui/windows/MusicController.java | 1 + 13 files changed, 78 insertions(+), 125 deletions(-) diff --git a/build.gradle b/build.gradle index d217424..d0e1c1e 100755 --- a/build.gradle +++ b/build.gradle @@ -68,18 +68,15 @@ project(":android") { project(":core") { apply plugin: "java" - - dependencies { compile "com.badlogicgames.gdx:gdx:$gdxVersion" compile "com.badlogicgames.gdx:gdx-freetype:$gdxVersion" - compile group: 'com.googlecode.soundlibs', name: 'mp3spi', version: '1.9.5.4' - + compile group: 'com.badlogicgames.jlayer', name: 'jlayer', version: '1.0.1-gdx' compile "org.apache.commons:commons-math3:3.2" compile "com.github.rwl:jtransforms:2.4.0" - + compile "org:jaudiotagger:2.0.3" } } diff --git a/core/src/zero1hd/rhythmbullet/audio/AudioAnalyzer.java b/core/src/zero1hd/rhythmbullet/audio/AudioAnalyzer.java index 46e12f1..5b5d952 100755 --- a/core/src/zero1hd/rhythmbullet/audio/AudioAnalyzer.java +++ b/core/src/zero1hd/rhythmbullet/audio/AudioAnalyzer.java @@ -90,7 +90,7 @@ public class AudioAnalyzer { mThresholdCalcRange = thresholdRangeCalc(0.4f); umThresholdCalcRange = thresholdRangeCalc(0.4f); - Gdx.app.debug("Read freq", String.valueOf(audioData.getFormat().getSampleRate())); + Gdx.app.debug("Read freq", String.valueOf(audioData.getSampleRate())); Gdx.app.debug("Using following bin ranges", "\nBass freq begin: " + bassBinBegin + "\nBass freq end: " + bassBinEnd + "\nMain freq begin: " + umBinBegin + "\nMain freq end: " + umBinEnd); @@ -221,7 +221,7 @@ public class AudioAnalyzer { } Gdx.app.debug("Audio Analyzer", "Data prunned."); - secondsPerWindow = audioData.getReadWindowSize()/audioData.getFormat().getSampleRate(); + secondsPerWindow = audioData.getReadWindowSize()/audioData.getSampleRate(); //peak detection int lastID = 0; @@ -349,7 +349,7 @@ public class AudioAnalyzer { } private int thresholdRangeCalc(float durationOfRange) { - return (int) (durationOfRange/(audioData.getReadWindowSize()/audioData.getFormat().getSampleRate())); + return (int) (durationOfRange/(audioData.getReadWindowSize()/audioData.getSampleRate())); } public float getBassMaxValue() { diff --git a/core/src/zero1hd/rhythmbullet/audio/AudioData.java b/core/src/zero1hd/rhythmbullet/audio/AudioData.java index 05195ce..73258bc 100755 --- a/core/src/zero1hd/rhythmbullet/audio/AudioData.java +++ b/core/src/zero1hd/rhythmbullet/audio/AudioData.java @@ -1,7 +1,5 @@ package zero1hd.rhythmbullet.audio; -import javax.sound.sampled.AudioFormat; - import com.badlogic.gdx.audio.Music; import com.badlogic.gdx.utils.Disposable; @@ -42,12 +40,6 @@ public interface AudioData extends Disposable { */ public int readSamples(float[] samples); - /** - * Returns properly setup AudioFormat object. - * @return - */ - public AudioFormat getFormat(); - /** * returns sample count * @return @@ -59,4 +51,10 @@ public interface AudioData extends Disposable { * @return */ public float getDuration(); + + /** + * returns sample rate + * @return sample rate as float + */ + public float getSampleRate(); } diff --git a/core/src/zero1hd/rhythmbullet/audio/Mp3AudioData.java b/core/src/zero1hd/rhythmbullet/audio/Mp3AudioData.java index e8e0c32..bc57dc7 100755 --- a/core/src/zero1hd/rhythmbullet/audio/Mp3AudioData.java +++ b/core/src/zero1hd/rhythmbullet/audio/Mp3AudioData.java @@ -1,14 +1,6 @@ package zero1hd.rhythmbullet.audio; -import java.io.File; import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.UnsupportedAudioFileException; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; @@ -19,54 +11,45 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.audio.Music; import com.badlogic.gdx.files.FileHandle; -import javazoom.jl.decoder.Decoder; +import javazoom.jl.decoder.Bitstream; +import javazoom.jl.decoder.BitstreamException; +import javazoom.jl.decoder.DecoderException; +import javazoom.jl.decoder.MP3Decoder; +import javazoom.jl.decoder.OutputBuffer; public class Mp3AudioData implements AudioData { private int readWindowSize = 1024; - private AudioInputStream din; - - private AudioFormat decodedFormat; private Music playbackMusic; private int readIndex; - + + private int sampleRate; private int sampleCount; private float durationInSeconds; - private AudioInputStream in; - - Decoder decoder = new Decoder(); + Bitstream bitStream; + MP3Decoder decoder; public Mp3AudioData(FileHandle audioFile) { try { MP3File mp3File = new MP3File(audioFile.file()); sampleCount = (int) mp3File.getMP3AudioHeader().getNumberOfFrames(); durationInSeconds = mp3File.getMP3AudioHeader().getNumberOfFrames()/readWindowSize; + sampleRate = mp3File.getMP3AudioHeader().getSampleRateAsNumber(); + + bitStream = new Bitstream(audioFile.read()); + decoder = new MP3Decoder(); } catch (IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e1) { e1.printStackTrace(); } - reset(); - try { - File file = audioFile.file(); - in = AudioSystem.getAudioInputStream(file); - din = null; - AudioFormat baseFormat = in.getFormat(); - decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16, - baseFormat.getChannels(), baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false); - din = AudioSystem.getAudioInputStream(decodedFormat, in); - } catch (UnsupportedAudioFileException | IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - playbackMusic = Gdx.audio.newMusic(audioFile); } @Override public void readIndexUpdate() { - readIndex = (int) (playbackMusic.getPosition() * decodedFormat.getSampleRate() / readWindowSize); + readIndex = (int) (playbackMusic.getPosition() * sampleRate / readWindowSize); } @Override @@ -76,9 +59,7 @@ public class Mp3AudioData implements AudioData { @Override public void reset() { - if (playbackMusic != null) { - playbackMusic.stop(); - } + playbackMusic.stop(); } @Override @@ -91,48 +72,6 @@ public class Mp3AudioData implements AudioData { return playbackMusic; } - byte[] toBeConverted = new byte[2]; - - @Override - public int readSamples(float[] samples) { - int samplesRead = 0; - short sampleAverage = 0; - - - for (int currentSample = 0; currentSample < samples.length; currentSample++) { - for (int channel = 0; channel < decodedFormat.getChannels(); channel++) { - try { - int readCount = din.read(toBeConverted, 0, toBeConverted.length); - - ByteBuffer bBuffer = ByteBuffer.allocate(2); - bBuffer.order(ByteOrder.LITTLE_ENDIAN); - bBuffer.put(toBeConverted[0]); - bBuffer.put(toBeConverted[1]); - - sampleAverage += bBuffer.getShort(0); - - if (readCount == -1) { - break; - } - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - sampleAverage /= decodedFormat.getChannels() * Short.MAX_VALUE + 1; - samples[currentSample] = sampleAverage; - sampleAverage = 0; - samplesRead++; - } - return samplesRead; - } - - @Override - public AudioFormat getFormat() { - return decodedFormat; - } - @Override public int getSampleCount() { return sampleCount; @@ -142,15 +81,6 @@ public class Mp3AudioData implements AudioData { public void dispose() { reset(); playbackMusic.dispose(); - if (din != null) { - try { - din.close(); - in.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } } @Override @@ -158,4 +88,33 @@ public class Mp3AudioData implements AudioData { return durationInSeconds; } + @Override + public int readSamples(float[] samples) { + int samplesRead = 0; + try { + OutputBuffer samplesBuffer = decoder.decodeFrame(bitStream.readFrame(), bitStream); + byte[] frameBuffer = samplesBuffer.getBuffer(); + for (int sampleID = 0; sampleID < samples.length; sampleID++) { + + samples[sampleID] += (short) ((frameBuffer[1] << 8) + (frameBuffer[0] & 0xff)); + if (samplesBuffer.isStereo()) { + samples[sampleID] = (short) ((frameBuffer[3] << 8) + (frameBuffer[2] & 0xff)); + + samples[sampleID] /= 2; + } + + samples[sampleID] /= Short.MAX_VALUE+1; + samplesRead ++; + } + } catch (DecoderException | BitstreamException e) { + e.printStackTrace(); + } + return samplesRead; + } + + @Override + public float getSampleRate() { + return sampleRate; + } + } diff --git a/core/src/zero1hd/rhythmbullet/audio/WavAudioData.java b/core/src/zero1hd/rhythmbullet/audio/WavAudioData.java index b82f9b4..08fd011 100755 --- a/core/src/zero1hd/rhythmbullet/audio/WavAudioData.java +++ b/core/src/zero1hd/rhythmbullet/audio/WavAudioData.java @@ -64,11 +64,6 @@ public class WavAudioData implements AudioData { return decoder.readSamples(samples); } - @Override - public AudioFormat getFormat() { - return format; - } - @Override public int getSampleCount() { return decoder.getDataSize()/(2*decoder.getChannels()); @@ -85,4 +80,9 @@ public class WavAudioData implements AudioData { public float getDuration() { return decoder.getDurationInSeconds(); } + + @Override + public float getSampleRate() { + return format.getSampleRate(); + } } diff --git a/core/src/zero1hd/rhythmbullet/audio/map/RhythmMapAlgorithm.java b/core/src/zero1hd/rhythmbullet/audio/map/RhythmMapAlgorithm.java index 8ca22aa..5cbd5e0 100755 --- a/core/src/zero1hd/rhythmbullet/audio/map/RhythmMapAlgorithm.java +++ b/core/src/zero1hd/rhythmbullet/audio/map/RhythmMapAlgorithm.java @@ -114,13 +114,6 @@ public class RhythmMapAlgorithm implements Runnable { esi.parameters.put("fuse", avgSPB*10f); esi.parameters.put("angle", angle); } else { - float xSpawnLocation = (rand.nextFloat()*(RhythmBullet.GAME_AREA_WIDTH-2))+1; - - esi = map.addEntity(em.pellet, null); - esi.parameters.put("x", xSpawnLocation); - esi.parameters.put("y", RhythmBullet.GAME_AREA_HEIGHT-0.25f); - esi.parameters.put("angle", 140*rand.nextFloat()+200f); - esi.parameters.put("speed", (RhythmBullet.GAME_AREA_HEIGHT/8f)/avgSPB); } } diff --git a/core/src/zero1hd/rhythmbullet/entity/Entity.java b/core/src/zero1hd/rhythmbullet/entity/Entity.java index 846fc82..96be070 100755 --- a/core/src/zero1hd/rhythmbullet/entity/Entity.java +++ b/core/src/zero1hd/rhythmbullet/entity/Entity.java @@ -158,6 +158,7 @@ public class Entity extends Actor implements Poolable { sprite.setPosition(0, 0); hitbox.set(0, 0, 0, 0); sprite.setRotation(0); + sprite.setColor(Color.WHITE); setPosition(0, 0); center.set(0, 0); angle = 0; diff --git a/core/src/zero1hd/rhythmbullet/entity/enemies/Flake.java b/core/src/zero1hd/rhythmbullet/entity/enemies/Flake.java index eb4f047..9b33350 100755 --- a/core/src/zero1hd/rhythmbullet/entity/enemies/Flake.java +++ b/core/src/zero1hd/rhythmbullet/entity/enemies/Flake.java @@ -37,7 +37,6 @@ public class Flake extends Entity { this.timer = fuse; this.totalTime = fuse; this.angle = angle; - hitbox.setSize(getWidth(), getHeight()); setPosition(x-getWidth()/2f, y-getHeight()/2f); } @@ -86,7 +85,7 @@ public class Flake extends Entity { @Override public void draw(Batch batch, float parentAlpha) { - sprite.setColor(0.1f,0.1f,0.1f, timer/totalTime); + sprite.setColor(0f, 0f, 0f, 1-(timer/totalTime)); super.draw(batch, parentAlpha); } @@ -109,7 +108,6 @@ public class Flake extends Entity { public void reset() { timer = 0; shards = null; - hitbox.set(0, 0, 0, 0); totalTime = 0; super.reset(); } diff --git a/core/src/zero1hd/rhythmbullet/entity/enemies/Shard.java b/core/src/zero1hd/rhythmbullet/entity/enemies/Shard.java index 90f6b3b..5669b5c 100755 --- a/core/src/zero1hd/rhythmbullet/entity/enemies/Shard.java +++ b/core/src/zero1hd/rhythmbullet/entity/enemies/Shard.java @@ -72,6 +72,8 @@ public class Shard extends Entity { public void collided(Entity entity) { if (entity.getClass() == Laser.class) { hp --; + } else { + dead = true; } } diff --git a/core/src/zero1hd/rhythmbullet/screens/CreativeScreen.java b/core/src/zero1hd/rhythmbullet/screens/CreativeScreen.java index f3300df..bea2c12 100755 --- a/core/src/zero1hd/rhythmbullet/screens/CreativeScreen.java +++ b/core/src/zero1hd/rhythmbullet/screens/CreativeScreen.java @@ -47,7 +47,7 @@ public class CreativeScreen extends ScreenAdapter { @Override public void render(float delta) { Gdx.gl.glClearColor(0.2f, 0.2f, 0.2f, 1f); - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); bgBatch.begin(); bgBatch.draw(background, 0f, 0f); diff --git a/core/src/zero1hd/rhythmbullet/screens/GameScreen.java b/core/src/zero1hd/rhythmbullet/screens/GameScreen.java index 0f093f7..c705c57 100755 --- a/core/src/zero1hd/rhythmbullet/screens/GameScreen.java +++ b/core/src/zero1hd/rhythmbullet/screens/GameScreen.java @@ -95,7 +95,7 @@ public class GameScreen extends ScreenAdapter { @Override public void render(float delta) { Gdx.gl.glClearColor(0f, 0f, 0f, 0f); - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); //Background stuff should literally span the whole screen so no matrice stuff bgBatch.begin(); if (bgShader != null) { diff --git a/core/src/zero1hd/rhythmbullet/ui/stages/GameHUD.java b/core/src/zero1hd/rhythmbullet/ui/stages/GameHUD.java index 246f712..82ca85d 100755 --- a/core/src/zero1hd/rhythmbullet/ui/stages/GameHUD.java +++ b/core/src/zero1hd/rhythmbullet/ui/stages/GameHUD.java @@ -120,14 +120,18 @@ public class GameHUD extends Stage { setScore(sm.getScore()); } - if (gpa.getAudioMap() != null && gpa.getAudioMap().getHudType()[gpa.getAudioMap().getIndex()] != 0) { - switch (gpa.getAudioMap().getHudType()[gpa.getAudioMap().getIndex()]) { - case 1: - changeStatusColor(bass, 0.2f, original); - break; - case 2: - changeStatusColor(um, 0.2f, original); + try { + if (gpa.getAudioMap() != null && gpa.getAudioMap().getHudType()[gpa.getAudioMap().getIndex()] != 0) { + switch (gpa.getAudioMap().getHudType()[gpa.getAudioMap().getIndex()]) { + case 1: + changeStatusColor(bass, 0.2f, original); + break; + case 2: + changeStatusColor(um, 0.2f, original); + } } + } catch (ArrayIndexOutOfBoundsException e) { + Gdx.app.debug("GameHUD", "reached end of status data."); } super.act(delta); } diff --git a/core/src/zero1hd/rhythmbullet/ui/windows/MusicController.java b/core/src/zero1hd/rhythmbullet/ui/windows/MusicController.java index 61137b7..839de51 100755 --- a/core/src/zero1hd/rhythmbullet/ui/windows/MusicController.java +++ b/core/src/zero1hd/rhythmbullet/ui/windows/MusicController.java @@ -121,6 +121,7 @@ public class MusicController extends Window implements OnCompletionListener { info.setText("Ready."); audiofile.getPlaybackMusic().play(); audiofile.getPlaybackMusic().pause(); + audiofile.getPlaybackMusic().setOnCompletionListener(this); } }