proper synchronization for reading samples; change to sample processor
interface to avoid creating unnessecary io streams; minor cleanup;
This commit is contained in:
parent
78324045f0
commit
55cac998ed
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
/**
|
||||
* <b>Should be thread-safe!</b>
|
||||
* <b>Thread safe</b>
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* <b>Should be thread-safe!</b>
|
||||
* <b>Thread safe</b>
|
||||
* ranges from 0 to 1.
|
||||
* @param volume the volume to set
|
||||
*/
|
||||
public void setVolume(float volume);
|
||||
|
||||
/**
|
||||
* <b>Should be thread-safe!</b>
|
||||
* <b>Thread safe</b>
|
||||
* @return the volume ranging from 0 to 1
|
||||
*/
|
||||
public float getVolume();
|
||||
|
||||
/**
|
||||
* <b>Should be thread-safe!</b>
|
||||
* <b>Thread safe</b>
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* <b>Should be thread-safe!</b>
|
||||
* <b>Thread safe</b>
|
||||
* Returns the pan value from -1 to 1.
|
||||
* see {@link #setPan(float)} for more information.
|
||||
* @return the pan value.
|
||||
|
@ -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,7 +45,9 @@ public class WAVSampleProcessor implements SampleProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int readSamples(short[] pcm) {
|
||||
public int readSamples(short[] pcm, Object syncObj) {
|
||||
if (initiated) {
|
||||
synchronized (syncObj) {
|
||||
int framesRead = 0;
|
||||
for (int sampleID = 0; sampleID < pcm.length; sampleID++) {
|
||||
try {
|
||||
@ -54,6 +69,10 @@ public class WAVSampleProcessor implements SampleProcessor {
|
||||
}
|
||||
return framesRead;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Stream has not been initialized.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVolume(float volume) {
|
||||
@ -74,4 +93,10 @@ public class WAVSampleProcessor implements SampleProcessor {
|
||||
public float getPan() {
|
||||
return pan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user