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 { public class Mp3Manager implements MusicManager {
private int readWindowSize = 1024; private int readWindowSize = 1024;
private Music music; private Music music;
private int playbackIndex; private int playbackIndex, readIndex;
private FileHandle fileHandle; private FileHandle fileHandle;
AudioInputStream in;
private AudioInputStream ais; private AudioInputStream ais;
private AudioFormat af; private AudioFormat af;
private AudioSampleReader d; private AudioSampleReader d;
@ -32,7 +33,6 @@ public class Mp3Manager implements MusicManager {
public Mp3Manager(FileHandle file) { public Mp3Manager(FileHandle file) {
this.fileHandle = file; this.fileHandle = file;
try { try {
AudioInputStream in;
in = AudioSystem.getAudioInputStream(file.file()); in = AudioSystem.getAudioInputStream(file.file());
AudioFormat baseFormat = in.getFormat(); AudioFormat baseFormat = in.getFormat();
properties = ((TAudioFormat)baseFormat).properties(); properties = ((TAudioFormat)baseFormat).properties();
@ -43,7 +43,6 @@ public class Mp3Manager implements MusicManager {
baseFormat.getChannels()*2, baseFormat.getChannels()*2,
baseFormat.getSampleRate(), false); baseFormat.getSampleRate(), false);
ais = AudioSystem.getAudioInputStream(baseFormat, in); ais = AudioSystem.getAudioInputStream(baseFormat, in);
in.close();
d = new AudioSampleReader(ais); d = new AudioSampleReader(ais);
music = Gdx.audio.newMusic(file); music = Gdx.audio.newMusic(file);
} catch (UnsupportedAudioFileException | IOException e) { } catch (UnsupportedAudioFileException | IOException e) {
@ -56,6 +55,7 @@ public class Mp3Manager implements MusicManager {
music.dispose(); music.dispose();
try { try {
ais.close(); ais.close();
in.close();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -79,6 +79,7 @@ public class Mp3Manager implements MusicManager {
@Override @Override
public int readSamples(float[] samples) { public int readSamples(float[] samples) {
try { try {
readIndex++;
return d.readSamples(samples); return d.readSamples(samples);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@ -152,22 +153,10 @@ public class Mp3Manager implements MusicManager {
return fileHandle; return fileHandle;
} }
@Override
public void seek(long position) { public void seek(long position) {
long totalSkipped = 0;
long skipped = 0;
closeStream(); closeStream();
reInitStream(); reInitStream();
while (totalSkipped < position) { skip(position);
try {
skipped = ais.skip(position-totalSkipped);
} catch (IOException e) {
e.printStackTrace();
}
if (skipped == 0) break;
totalSkipped += skipped;
}
} }
private void closeStream() { private void closeStream() {
@ -194,4 +183,32 @@ public class Mp3Manager implements MusicManager {
public void synchronize() { public void synchronize() {
seek(MathUtils.round(((Integer) properties.get("audio.length.bytes")).intValue() * (getPositionInSeconds()/getDuration()))); 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(); 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 * Synchronizes the playback and read threads
*/ */
public void synchronize(); 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 { public class WAVManager implements MusicManager {
private int readWindowSize = 1024; private int readWindowSize = 1024;
private int playbackIndex; private int playbackIndex, readIndex;
private Music music; private Music music;
private FileHandle fileHandle; private FileHandle fileHandle;
private AudioInputStream ais; private AudioInputStream ais;
@ -64,6 +64,7 @@ public class WAVManager implements MusicManager {
@Override @Override
public int readSamples(float[] samples) { public int readSamples(float[] samples) {
try { try {
readIndex++;
return d.readSamples(samples); return d.readSamples(samples);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@ -136,22 +137,9 @@ public class WAVManager implements MusicManager {
return fileHandle; return fileHandle;
} }
@Override
public void seek(long position) { public void seek(long position) {
long totalSkipped = 0;
long skipped = 0;
restartStream(); restartStream();
while (totalSkipped < position) { skip(position);
try {
skipped = ais.skip(position-totalSkipped);
} catch (IOException e) {
e.printStackTrace();
}
if (skipped == 0) break;
totalSkipped += skipped;
}
} }
private void restartStream() { private void restartStream() {
@ -162,9 +150,7 @@ public class WAVManager implements MusicManager {
} }
try { try {
AudioInputStream in = AudioSystem.getAudioInputStream(fileHandle.file()); ais = AudioSystem.getAudioInputStream(fileHandle.file());
ais = AudioSystem.getAudioInputStream(af, in);
in.close();
} catch (UnsupportedAudioFileException | IOException e) { } catch (UnsupportedAudioFileException | IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -173,5 +159,32 @@ public class WAVManager implements MusicManager {
@Override @Override
public void synchronize() { public void synchronize() {
seek(MathUtils.round(getPositionInSeconds()*getSampleRate())); 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; updateTimer += delta;
if (updateTimer >= updateRate) { if (updateTimer >= updateRate) {
mm.playbackIndexUpdate(); mm.playbackIndexUpdate();
while (mm.getPlaybackIndexPosition() > mm.getReadIndex()) {
mm.skipReadWindow();
}
lock.lock(); lock.lock();
mm.setReadIndexToPlaybackIndex();
mm.readSamples(audioPCM); mm.readSamples(audioPCM);
fft.realForward(audioPCM); fft.realForward(audioPCM);
lock.unlock(); lock.unlock();

View File

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