UNTESTED; basic mp3spi setup done; more efficient way of skipping bytes now; syncing of playback and read implemented

This commit is contained in:
Harrison Deng 2017-12-15 23:56:38 -06:00
parent 677ada45b6
commit cebf36dff9
5 changed files with 109 additions and 59 deletions

View File

@ -22,8 +22,9 @@ import zero1hd.rhythmbullet.audio.wavedecoder.AudioSampleReader;
public class Mp3Manager implements MusicManager {
private int readWindowSize = 1024;
private Music music;
private int playbackIndex;
private int playbackIndex, readIndex;
private FileHandle fileHandle;
AudioInputStream in;
private AudioInputStream ais;
private AudioFormat af;
private AudioSampleReader d;
@ -32,7 +33,6 @@ public class Mp3Manager implements MusicManager {
public Mp3Manager(FileHandle file) {
this.fileHandle = file;
try {
AudioInputStream in;
in = AudioSystem.getAudioInputStream(file.file());
AudioFormat baseFormat = in.getFormat();
properties = ((TAudioFormat)baseFormat).properties();
@ -43,7 +43,6 @@ public class Mp3Manager implements MusicManager {
baseFormat.getChannels()*2,
baseFormat.getSampleRate(), false);
ais = AudioSystem.getAudioInputStream(baseFormat, in);
in.close();
d = new AudioSampleReader(ais);
music = Gdx.audio.newMusic(file);
} catch (UnsupportedAudioFileException | IOException e) {
@ -56,6 +55,7 @@ public class Mp3Manager implements MusicManager {
music.dispose();
try {
ais.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
@ -79,6 +79,7 @@ public class Mp3Manager implements MusicManager {
@Override
public int readSamples(float[] samples) {
try {
readIndex++;
return d.readSamples(samples);
} catch (IOException e) {
e.printStackTrace();
@ -152,22 +153,10 @@ public class Mp3Manager implements MusicManager {
return fileHandle;
}
@Override
public void seek(long position) {
long totalSkipped = 0;
long skipped = 0;
closeStream();
reInitStream();
while (totalSkipped < position) {
try {
skipped = ais.skip(position-totalSkipped);
} catch (IOException e) {
e.printStackTrace();
}
if (skipped == 0) break;
totalSkipped += skipped;
}
skip(position);
}
private void closeStream() {
@ -194,4 +183,32 @@ public class Mp3Manager implements MusicManager {
public void synchronize() {
seek(MathUtils.round(((Integer) properties.get("audio.length.bytes")).intValue() * (getPositionInSeconds()/getDuration())));
}
@Override
public int getReadIndex() {
return readIndex;
}
public void skip(long bytes) {
long totalSkipped = 0;
long skipped = 0;
while (totalSkipped < bytes) {
try {
skipped = ais.skip(bytes-totalSkipped);
} catch (IOException e) {
e.printStackTrace();
}
if (skipped == 0) break;
totalSkipped += skipped;
}
}
@Override
public void skipReadWindow() {
skip(readWindowSize*af.getFrameSize());
readIndex++;
}
}

View File

@ -82,14 +82,15 @@ public interface MusicManager extends Disposable {
*/
public FileHandle getMusicFile();
/**
* sets the reading position to the given position;
* @param position the byte to skip to.
*/
public void seek(long position);
/**
* Synchronizes the playback and read threads
*/
public void synchronize();
/**
* @return the window that the current read index is on
*/
public int getReadIndex();
public void skipReadWindow();
}

View File

@ -17,7 +17,7 @@ import zero1hd.rhythmbullet.audio.wavedecoder.AudioSampleReader;
public class WAVManager implements MusicManager {
private int readWindowSize = 1024;
private int playbackIndex;
private int playbackIndex, readIndex;
private Music music;
private FileHandle fileHandle;
private AudioInputStream ais;
@ -64,6 +64,7 @@ public class WAVManager implements MusicManager {
@Override
public int readSamples(float[] samples) {
try {
readIndex++;
return d.readSamples(samples);
} catch (IOException e) {
e.printStackTrace();
@ -136,22 +137,9 @@ public class WAVManager implements MusicManager {
return fileHandle;
}
@Override
public void seek(long position) {
long totalSkipped = 0;
long skipped = 0;
restartStream();
while (totalSkipped < position) {
try {
skipped = ais.skip(position-totalSkipped);
} catch (IOException e) {
e.printStackTrace();
}
if (skipped == 0) break;
totalSkipped += skipped;
}
skip(position);
}
private void restartStream() {
@ -162,9 +150,7 @@ public class WAVManager implements MusicManager {
}
try {
AudioInputStream in = AudioSystem.getAudioInputStream(fileHandle.file());
ais = AudioSystem.getAudioInputStream(af, in);
in.close();
ais = AudioSystem.getAudioInputStream(fileHandle.file());
} catch (UnsupportedAudioFileException | IOException e) {
e.printStackTrace();
}
@ -173,5 +159,32 @@ public class WAVManager implements MusicManager {
@Override
public void synchronize() {
seek(MathUtils.round(getPositionInSeconds()*getSampleRate()));
readIndex = playbackIndex;
}
@Override
public int getReadIndex() {
return readIndex;
}
public void skip(long bytes) {
long totalSkipped = 0;
long skipped = 0;
while (totalSkipped < bytes) {
try {
skipped = ais.skip(bytes-totalSkipped);
} catch (IOException e) {
e.printStackTrace();
}
if (skipped == 0) break;
totalSkipped += skipped;
}
}
@Override
public void skipReadWindow() {
skip(af.getFrameSize()*readWindowSize);
readIndex++;
}
}

View File

@ -33,8 +33,10 @@ public class VisualizerCore implements Disposable {
updateTimer += delta;
if (updateTimer >= updateRate) {
mm.playbackIndexUpdate();
while (mm.getPlaybackIndexPosition() > mm.getReadIndex()) {
mm.skipReadWindow();
}
lock.lock();
mm.setReadIndexToPlaybackIndex();
mm.readSamples(audioPCM);
fft.realForward(audioPCM);
lock.unlock();

View File

@ -8,8 +8,8 @@ public class AudioSampleReader {
private int channels;
private double sampleRate;
private byte[] buffer;
private int sampleSize;
private AudioInputStream audioInputStream;
private boolean mergeChannels;
public AudioSampleReader(AudioInputStream ais) throws IOException {
audioInputStream = ais;
@ -17,7 +17,6 @@ public class AudioSampleReader {
channels = audioInputStream.getFormat().getChannels();
sampleRate = audioInputStream.getFormat().getSampleRate();
sampleSize = audioInputStream.getFormat().getSampleSizeInBits();
}
public int getChannels() {
@ -28,30 +27,51 @@ public class AudioSampleReader {
return sampleRate;
}
public float getDurationInSeconds() {
return audioInputStream.getFrameLength()/audioInputStream.getFormat().getFrameRate();
}
public long getFrameLength() {
return audioInputStream.getFrameLength();
}
public int readSamples(float[] samples) throws IOException {
int framesRead = 0;
for (int sampleID = 0; sampleID < samples.length; sampleID++) {
if (audioInputStream.read(buffer) > 0) {
samples[sampleID] += (buffer[1] << 8) + (buffer[0] & 0x00ff);
if (audioInputStream.getFormat().getChannels() > 1) {
short altChan = (short) ((buffer[3] << 8) + (buffer[2] & 0x00ff));
if (mergeChannels) {
samples[sampleID] = altChan > samples[sampleID] ? altChan : samples[sampleID];
} else {
sampleID++;
samples[sampleID] = altChan;
}
}
framesRead ++;
samples[sampleID] /= Short.MAX_VALUE+1;
}
}
return framesRead;
}
public int readSamples(short[] samples) throws IOException {
int framesRead = 0;
for (int sampleID = 0; sampleID < samples.length; sampleID++) {
if (audioInputStream.read(buffer) > 0) {
samples[sampleID] += (buffer[1] << 8) + (buffer[0] & 0x00ff);
if (audioInputStream.getFormat().getChannels() > 1) {
short altChan = (short) ((buffer[3] << 8) + (buffer[2] & 0x00ff));
samples[sampleID] = altChan > samples[sampleID] ? altChan : samples[sampleID];
if (mergeChannels) {
samples[sampleID] = altChan > samples[sampleID] ? altChan : samples[sampleID];
} else {
sampleID++;
samples[sampleID] = altChan;
}
}
framesRead ++;
samples[sampleID] /= Short.MAX_VALUE+1;
}
}
return framesRead;
}
@ -59,15 +79,12 @@ public class AudioSampleReader {
return audioInputStream;
}
public int getSampleSizeInBits() {
return sampleSize;
public void setMergeChannels(boolean mergeChannels) {
this.mergeChannels = mergeChannels;
}
public boolean isMergeChannels() {
return mergeChannels;
}
public void cleanAndClose() {
try {
audioInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}