diff --git a/core/src/zero1hd/rhythmbullet/audio/RhythmBulletAudioThread.java b/core/src/zero1hd/rhythmbullet/audio/RhythmBulletAudioThread.java
index ad744c6..fd24013 100755
--- a/core/src/zero1hd/rhythmbullet/audio/RhythmBulletAudioThread.java
+++ b/core/src/zero1hd/rhythmbullet/audio/RhythmBulletAudioThread.java
@@ -20,13 +20,14 @@ public class RhythmBulletAudioThread extends Thread {
music = vm;
this.sp = vm.getSampleProcessor();
pcm = new short[sp.getChannels()*windowSize];
-
- this.ad = Gdx.audio.newAudioDevice(sp.getSampleRate(), (sp.getChannels() > 1 ? false : true));
}
@Override
public void run() {
- while (!terminated && sp.readSamples(pcm) > 0) {
+ sp.initiate();
+ this.ad = Gdx.audio.newAudioDevice(sp.getSampleRate(), (sp.getChannels() > 1 ? false : true));
+
+ while (!terminated && sp.readSamples(pcm, this) > 0) {
ad.writeSamples(pcm, 0, pcm.length);
}
diff --git a/core/src/zero1hd/rhythmbullet/audio/VisualizableMusic.java b/core/src/zero1hd/rhythmbullet/audio/VisualizableMusic.java
index 06bd956..f1fa4a8 100755
--- a/core/src/zero1hd/rhythmbullet/audio/VisualizableMusic.java
+++ b/core/src/zero1hd/rhythmbullet/audio/VisualizableMusic.java
@@ -29,7 +29,7 @@ public class VisualizableMusic implements Music {
e.printStackTrace();
}
} else if (musicFile.getName().toLowerCase().endsWith("mp3")) {
- sampleProcessor = new MP3SampleProcessor();
+ sampleProcessor = new MP3SampleProcessor(musicFile, windowSize);
}
}
@@ -38,8 +38,10 @@ public class VisualizableMusic implements Music {
if (rat == null) {
rat = new RhythmBulletAudioThread(windowSize, this);
}
+
rat.setOnCompletionListener(ocl);
rat.play();
+ rat.start();
}
@Override
@@ -105,6 +107,9 @@ public class VisualizableMusic implements Music {
@Override
public void setOnCompletionListener(OnCompletionListener listener) {
this.ocl = listener;
+ if (rat != null) {
+ rat.setOnCompletionListener(listener);
+ }
}
protected SampleProcessor getSampleProcessor() {
diff --git a/core/src/zero1hd/rhythmbullet/audio/processor/MP3SampleProcessor.java b/core/src/zero1hd/rhythmbullet/audio/processor/MP3SampleProcessor.java
index 119a0d1..e3d8ceb 100755
--- a/core/src/zero1hd/rhythmbullet/audio/processor/MP3SampleProcessor.java
+++ b/core/src/zero1hd/rhythmbullet/audio/processor/MP3SampleProcessor.java
@@ -1,6 +1,25 @@
package zero1hd.rhythmbullet.audio.processor;
+import java.io.File;
+
public class MP3SampleProcessor implements SampleProcessor {
+ private int channels;
+
+ public MP3SampleProcessor(File musicFile, int windowSize) {
+
+ }
+
+ @Override
+ public void dispose() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void initiate() {
+ // TODO Auto-generated method stub
+
+ }
@Override
public int getChannels() {
@@ -15,7 +34,7 @@ public class MP3SampleProcessor implements SampleProcessor {
}
@Override
- public int readSamples(short[] pcm) {
+ public int readSamples(short[] pcm, Object syncObj) {
// TODO Auto-generated method stub
return 0;
}
@@ -43,4 +62,5 @@ public class MP3SampleProcessor implements SampleProcessor {
// TODO Auto-generated method stub
return 0;
}
+
}
diff --git a/core/src/zero1hd/rhythmbullet/audio/processor/SampleProcessor.java b/core/src/zero1hd/rhythmbullet/audio/processor/SampleProcessor.java
index 40ef69d..983d90d 100755
--- a/core/src/zero1hd/rhythmbullet/audio/processor/SampleProcessor.java
+++ b/core/src/zero1hd/rhythmbullet/audio/processor/SampleProcessor.java
@@ -1,6 +1,15 @@
package zero1hd.rhythmbullet.audio.processor;
-public interface SampleProcessor {
+import com.badlogic.gdx.utils.Disposable;
+
+public interface SampleProcessor extends Disposable {
+
+ /**
+ * Called once, contains the initiation to the stream, only called when play-back begins.
+ * Not thread safe as it should be the first thing to be called during read process.
+ */
+ public void initiate();
+
/**
* @return number of channels
*/
@@ -12,29 +21,30 @@ public interface SampleProcessor {
public int getSampleRate();
/**
- * Should be thread-safe!
+ * Thread safe
* Reads samples (NOT FRAMES) with interwoven data for stereo.
* stored in 16 bit format (first 8 are the first byte of data while the second 8 are the second byte of data that composes a short value)
* @param pcm the array the samples should fill
+ * @param syncObj the object that this object should use to synchronize multiple threads.
* @return the amount of samples read.
*/
- public int readSamples(short[] pcm);
+ public int readSamples(short[] pcm, Object syncObj);
/**
- * Should be thread-safe!
+ * Thread safe
* ranges from 0 to 1.
* @param volume the volume to set
*/
public void setVolume(float volume);
/**
- * Should be thread-safe!
+ * Thread safe
* @return the volume ranging from 0 to 1
*/
public float getVolume();
/**
- * Should be thread-safe!
+ * Thread safe
* sets the pan from the left channel to the right.
* ranges from -1 to 1.
* Default is 0, -1 is left, 1 is right.
@@ -43,7 +53,7 @@ public interface SampleProcessor {
public void setPan(float pan);
/**
- * Should be thread-safe!
+ * Thread safe
* Returns the pan value from -1 to 1.
* see {@link #setPan(float)} for more information.
* @return the pan value.
diff --git a/core/src/zero1hd/rhythmbullet/audio/processor/WAVSampleProcessor.java b/core/src/zero1hd/rhythmbullet/audio/processor/WAVSampleProcessor.java
index 6923e4d..2c92ae4 100755
--- a/core/src/zero1hd/rhythmbullet/audio/processor/WAVSampleProcessor.java
+++ b/core/src/zero1hd/rhythmbullet/audio/processor/WAVSampleProcessor.java
@@ -3,6 +3,7 @@ package zero1hd.rhythmbullet.audio.processor;
import java.io.File;
import java.io.IOException;
+import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
@@ -11,18 +12,30 @@ public class WAVSampleProcessor implements SampleProcessor {
private int channels;
private int sampleRate;
private byte[] buffer;
+ private File file;
private AudioInputStream audioInputStream;
private volatile float volume, pan;
+ private volatile boolean initiated;
public WAVSampleProcessor(File musicFile, int windowSize) throws IOException, UnsupportedAudioFileException {
- audioInputStream = AudioSystem.getAudioInputStream(musicFile);
- buffer = new byte[audioInputStream.getFormat().getFrameSize()];
-
- channels = audioInputStream.getFormat().getChannels();
- sampleRate = (int) audioInputStream.getFormat().getSampleRate();
+ this.file = musicFile;
+ AudioFormat format = AudioSystem.getAudioFileFormat(file).getFormat();
+ channels = format.getChannels();
+ sampleRate = (int) format.getSampleRate();
volume = 1f;
}
+ @Override
+ public void initiate() {
+ try {
+ audioInputStream = AudioSystem.getAudioInputStream(file);
+ } catch (UnsupportedAudioFileException | IOException e) {
+ e.printStackTrace();
+ }
+ buffer = new byte[audioInputStream.getFormat().getFrameSize()];
+ initiated = true;
+ }
+
public int getChannels() {
return channels;
}
@@ -32,27 +45,33 @@ public class WAVSampleProcessor implements SampleProcessor {
}
@Override
- public synchronized int readSamples(short[] pcm) {
- int framesRead = 0;
- for (int sampleID = 0; sampleID < pcm.length; sampleID++) {
- try {
- if (audioInputStream.read(buffer) > 0) {
- pcm[sampleID] = (short) ((buffer[1] << 8) + (buffer[0] & 0x00ff));
- pcm[sampleID] *= volume * (Math.min(1-pan, 1));
- if (audioInputStream.getFormat().getChannels() > 1) {
- short secondChan = (short) ((buffer[3] << 8) + (buffer[2] & 0x00ff));
- secondChan *= volume * (Math.min(1+pan, 1));
- sampleID++;
- pcm[sampleID] = secondChan;
+ public int readSamples(short[] pcm, Object syncObj) {
+ if (initiated) {
+ synchronized (syncObj) {
+ int framesRead = 0;
+ for (int sampleID = 0; sampleID < pcm.length; sampleID++) {
+ try {
+ if (audioInputStream.read(buffer) > 0) {
+ pcm[sampleID] = (short) ((buffer[1] << 8) + (buffer[0] & 0x00ff));
+ pcm[sampleID] *= volume * (Math.min(1-pan, 1));
+ if (audioInputStream.getFormat().getChannels() > 1) {
+ short secondChan = (short) ((buffer[3] << 8) + (buffer[2] & 0x00ff));
+ secondChan *= volume * (Math.min(1+pan, 1));
+ sampleID++;
+ pcm[sampleID] = secondChan;
+ }
+ framesRead++;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
}
- framesRead++;
+
}
- } catch (IOException e) {
- e.printStackTrace();
+ return framesRead;
}
-
+ } else {
+ throw new IllegalStateException("Stream has not been initialized.");
}
- return framesRead;
}
@Override
@@ -74,4 +93,10 @@ public class WAVSampleProcessor implements SampleProcessor {
public float getPan() {
return pan;
}
+
+ @Override
+ public void dispose() {
+ // TODO Auto-generated method stub
+
+ }
}
\ No newline at end of file