From 5a472b21e6c8856e71133c5e04fbe4a29b41edcb Mon Sep 17 00:00:00 2001 From: Recrown Date: Tue, 18 Apr 2017 23:34:39 -0500 Subject: [PATCH] Began work on music selection UI --- build.gradle | 6 + .../zero1hd/polyjet/audio/WavAudioData.java | 35 +++--- .../polyjet/ui/builders/MusicSelectable.java | 61 +++++++++- core/src/zero1hd/wavedecoder/WavDecoder.java | 101 ++-------------- core/src/zero1hd/wavedecoder/WavInfo.java | 114 ++++++++++++++++++ 5 files changed, 203 insertions(+), 114 deletions(-) mode change 100644 => 100755 core/src/zero1hd/polyjet/ui/builders/MusicSelectable.java create mode 100755 core/src/zero1hd/wavedecoder/WavInfo.java diff --git a/build.gradle b/build.gradle index d73aba4..b8133b3 100755 --- a/build.gradle +++ b/build.gradle @@ -47,6 +47,8 @@ project(":desktop") { compile "org.apache.commons:commons-math3:3.2" compile "com.github.rwl:jtransforms:2.4.0" + + compile "com.mpatric:mp3agic:0.9.0" } } @@ -75,6 +77,8 @@ project(":android") { compile "org.apache.commons:commons-math3:3.2" compile "com.github.rwl:jtransforms:2.4.0" + + compile "com.mpatric:mp3agic:0.9.0" } } @@ -91,6 +95,8 @@ project(":core") { compile "org.apache.commons:commons-math3:3.2" compile "com.github.rwl:jtransforms:2.4.0" + + compile "com.mpatric:mp3agic:0.9.0" } } diff --git a/core/src/zero1hd/polyjet/audio/WavAudioData.java b/core/src/zero1hd/polyjet/audio/WavAudioData.java index 39d090d..1c8f102 100755 --- a/core/src/zero1hd/polyjet/audio/WavAudioData.java +++ b/core/src/zero1hd/polyjet/audio/WavAudioData.java @@ -1,8 +1,7 @@ package zero1hd.polyjet.audio; -import java.io.BufferedInputStream; import java.io.IOException; -import java.io.InputStream; +import java.security.InvalidParameterException; import javax.sound.sampled.AudioFormat; @@ -11,19 +10,19 @@ import com.badlogic.gdx.audio.Music; import com.badlogic.gdx.files.FileHandle; import zero1hd.wavedecoder.WavDecoder; +import zero1hd.wavedecoder.WavInfo; public class WavAudioData implements AudioData { private int readWindowSize = 1024; - private InputStream inStream; - private InputStream bufferedAudioIn; private AudioFormat format; int readIndex; Music playbackMusic; WavDecoder decoder; + WavInfo wavinfo; @Override public void readIndexUpdate() { - readIndex = (int) (playbackMusic.getPosition() * decoder.getSampleRate() / readWindowSize); + readIndex = (int) (playbackMusic.getPosition() * wavinfo.getSampleRate() / readWindowSize); } @Override @@ -31,15 +30,21 @@ public class WavAudioData implements AudioData { return readIndex; } + public void setInfo(WavInfo wavinfo) { + this.wavinfo = wavinfo; + } + @Override public void setAudioFile(FileHandle audioFileHandler) { reset(); - - inStream = audioFileHandler.read(); - bufferedAudioIn = new BufferedInputStream(inStream); - decoder.setAudioFile(audioFileHandler.file()); + try { + decoder.setAudioFile(wavinfo); + } catch (InvalidParameterException | IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } playbackMusic = Gdx.audio.newMusic(audioFileHandler); - format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, (float) decoder.getSampleRate(), 16, decoder.getChannels(), decoder.getChannels()*2, (float)decoder.getSampleRate(), false); + format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, (float) wavinfo.getSampleRate(), 16, wavinfo.getChannels(), wavinfo.getChannels()*2, (float) wavinfo.getSampleRate(), false); } @Override @@ -49,16 +54,6 @@ public class WavAudioData implements AudioData { playbackMusic.dispose(); playbackMusic = null; } - - if (inStream != null) { - try { - bufferedAudioIn.close(); - inStream.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } } @Override diff --git a/core/src/zero1hd/polyjet/ui/builders/MusicSelectable.java b/core/src/zero1hd/polyjet/ui/builders/MusicSelectable.java old mode 100644 new mode 100755 index 8429e9f..6c1b72b --- a/core/src/zero1hd/polyjet/ui/builders/MusicSelectable.java +++ b/core/src/zero1hd/polyjet/ui/builders/MusicSelectable.java @@ -1,16 +1,65 @@ package zero1hd.polyjet.ui.builders; -import com.badlogic.gdx.files.FileHandle; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.scenes.scene2d.Actor; -import com.badlogic.gdx.scenes.scene2d.ui.Image; +import java.io.IOException; -public class MusicSelectable extends Actor { +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.scenes.scene2d.ui.Image; +import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup; +import com.mpatric.mp3agic.ID3v2; +import com.mpatric.mp3agic.InvalidDataException; +import com.mpatric.mp3agic.Mp3File; +import com.mpatric.mp3agic.UnsupportedTagException; + +import zero1hd.wavedecoder.WavInfo; + +public class MusicSelectable extends WidgetGroup { Image imageIcon; FileHandle musicFile; + boolean invalidMusic; + long durationInSeconds; + String songName; + + WavInfo wavinfo; + public MusicSelectable(FileHandle musicFile) { this.musicFile = musicFile; - imageIcon = new Image(new Texture(musicFile)); + if (musicFile.extension().toLowerCase().equals("mp3")) { + try { + Mp3File mp3File = new Mp3File(musicFile.file()); + durationInSeconds = mp3File.getLengthInSeconds(); + + if (mp3File.hasId3v2Tag()) { + ID3v2 id3v2tag = mp3File.getId3v2Tag(); + byte[] albumWorkBytes = id3v2tag.getAlbumImage(); + + Pixmap albumArt = new Pixmap(albumWorkBytes, 0, albumWorkBytes.length); + Texture albumArtTexture = new Texture(albumArt); + imageIcon = new Image(albumArtTexture); + float scale = 0.25f*Gdx.graphics.getHeight()/imageIcon.getHeight(); + + imageIcon.setScale(scale); + albumArtTexture.dispose(); + + songName = id3v2tag.getTitle(); + } + } catch (UnsupportedTagException | InvalidDataException | IOException e) { + e.printStackTrace(); + } + } else { + wavinfo = new WavInfo(musicFile.file()); + durationInSeconds = wavinfo.getDurationInSeconds(); + } + if (durationInSeconds > 60 * 5) { + invalidMusic = true; + } + if (songName == null || songName.isEmpty()) { + songName = musicFile.name(); + } } + + } diff --git a/core/src/zero1hd/wavedecoder/WavDecoder.java b/core/src/zero1hd/wavedecoder/WavDecoder.java index f141ae1..a3ea1be 100755 --- a/core/src/zero1hd/wavedecoder/WavDecoder.java +++ b/core/src/zero1hd/wavedecoder/WavDecoder.java @@ -1,96 +1,16 @@ package zero1hd.wavedecoder; -import java.io.DataInputStream; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.security.InvalidParameterException; public class WavDecoder { - DataInputStream readStream; - private int channels; - private double sampleRate; - private int dataSize; - private int byteRate; + private WavInfo initialData; - public void setAudioFile(File file) throws InvalidParameterException { - try { - FileInputStream audioFile = new FileInputStream(file); - readStream = new DataInputStream(audioFile); - - if (!readBytesToString(4).equals("RIFF")) { - throw new InvalidParameterException("RIFF tag not found in header."); - } - dataSize = littleEndianIntBytes(); - - if (!readBytesToString(4).equals("WAVE")) { - throw new InvalidParameterException("WAVE format tag not found."); - } - - if (!readBytesToString(4).equals("fmt ")) { - throw new InvalidParameterException("fmt header not found."); - } - - if (readStream.readByte() != 16) { - throw new InvalidParameterException("Data not pcm?"); - } - - readStream.skipBytes(3); - if (readStream.readByte() != 1) { - throw new InvalidParameterException("Data not pcm?"); - } - readStream.skipBytes(1); - - channels = readStream.readByte(); - readStream.skipBytes(1); - - sampleRate = littleEndianIntBytes(); - - byteRate = littleEndianIntBytes(); - - readStream.skipBytes(38); - - if (!readBytesToString(4).equals("data")) { - throw new InvalidParameterException("initial data section tag not found"); - } - readStream.skipBytes(4); - } catch (IOException e) { - e.printStackTrace(); - } + public void setAudioFile(WavInfo info) throws InvalidParameterException, IOException { + initialData = info; + initialData.initDataStream(); + initialData.getHeaderInfo(); } - - private String readBytesToString(int bytesToRead) throws IOException { - byte byteString[] = new byte[bytesToRead]; - readStream.read(byteString); - return new String(byteString); - } - - private int littleEndianIntBytes() throws IOException { - int data = readStream.readInt(); - return Integer.reverseBytes(data); - } - - private short readLittleEndianShort() throws IOException { - short data = readStream.readShort(); - return Short.reverseBytes(data); - } - - public int getChannels() { - return channels; - } - - public double getSampleRate() { - return sampleRate; - } - - public int getByteRate() { - return byteRate; - } - - public int getDataSize() { - return dataSize; - } - public int readSamples(float[] samples) { int samplesRead = 0; @@ -98,13 +18,18 @@ public class WavDecoder { try { int currentSample = 0; - for (int channel = 0; channel < channels; channel++) { - currentSample += readLittleEndianShort(); + for (int channel = 0; channel < initialData.getChannels(); channel++) { + currentSample += initialData.readLittleEndianShort(); } - currentSample /= channels*Short.MAX_VALUE+1; + currentSample /= initialData.getChannels()*Short.MAX_VALUE+1; samples[i] = currentSample; samplesRead++; } catch (IOException e) { + try { + initialData.closeStreams(); + } catch (IOException e1) { + e1.printStackTrace(); + } break; } } diff --git a/core/src/zero1hd/wavedecoder/WavInfo.java b/core/src/zero1hd/wavedecoder/WavInfo.java new file mode 100755 index 0000000..9e4fe98 --- /dev/null +++ b/core/src/zero1hd/wavedecoder/WavInfo.java @@ -0,0 +1,114 @@ +package zero1hd.wavedecoder; + +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.InvalidParameterException; + +public class WavInfo { + private int channels; + private double sampleRate; + private int dataSize; + private int byteRate; + private FileInputStream audioFile; + private DataInputStream readStream; + + public WavInfo(File file) throws InvalidParameterException { + try { + audioFile = new FileInputStream(file); + initDataStream(); + getHeaderInfo(); + closeStreams(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + protected void getHeaderInfo() throws IOException { + if (!readBytesToString(4).equals("RIFF")) { //4 + throw new InvalidParameterException("RIFF tag not found in header."); + } + dataSize = littleEndianIntBytes(); //4 + + if (!readBytesToString(4).equals("WAVE")) { //4 + throw new InvalidParameterException("WAVE format tag not found."); + } + + if (!readBytesToString(4).equals("fmt ")) { //4 + throw new InvalidParameterException("fmt header not found."); + } + + if (readStream.readByte() != 16) { //1 + throw new InvalidParameterException("Data not pcm?"); + } + + readStream.skipBytes(3); //3 + if (readStream.readByte() != 1) { //1 + throw new InvalidParameterException("Data not pcm?"); + } + readStream.skipBytes(1); //1 + + channels = readStream.readByte(); //1 + readStream.skipBytes(1); //1 + + sampleRate = littleEndianIntBytes(); //4 + + byteRate = littleEndianIntBytes(); //4 + + readStream.skipBytes(38); //38 + + if (!readBytesToString(4).equals("data")) { // 4 + throw new InvalidParameterException("initial data section tag not found"); + } + } + + protected void initDataStream() { + readStream = new DataInputStream(audioFile); + } + + protected void closeStreams() throws IOException { + readStream.close(); + audioFile.close(); + } + + private String readBytesToString(int bytesToRead) throws IOException { + byte byteString[] = new byte[bytesToRead]; + readStream.read(byteString); + return new String(byteString); + } + + private int littleEndianIntBytes() throws IOException { + int data = readStream.readInt(); + return Integer.reverseBytes(data); + } + + protected short readLittleEndianShort() throws IOException { + short data = readStream.readShort(); + return Short.reverseBytes(data); + } + + protected DataInputStream getReadStream() { + return readStream; + } + + public int getChannels() { + return channels; + } + + public int getByteRate() { + return byteRate; + } + + public int getDataSize() { + return dataSize; + } + + public double getSampleRate() { + return sampleRate; + } + + public long getDurationInSeconds() { + return (long) (dataSize/sampleRate); + } +}