random access files now used to sync visualizer with song (optimization)

This commit is contained in:
Harrison Deng 2017-12-10 01:45:10 -06:00
parent 8023987148
commit 51ce146611
7 changed files with 93 additions and 53 deletions

View File

@ -1,6 +1,12 @@
package zero1hd.rhythmbullet.audio; package zero1hd.rhythmbullet.audio;
import java.io.BufferedInputStream;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.channels.Channels;
import java.security.InvalidParameterException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -30,9 +36,9 @@ import javazoom.jl.decoder.OutputBuffer;
public class Mp3Manager implements MusicManager { public class Mp3Manager implements MusicManager {
private int readWindowSize = 1024; private int readWindowSize = 1024;
private int currentReadWindowIndex; private int readWindowIndex;
private Music playbackMusic; private Music playbackMusic;
private int readIndex; private int playbackIndex;
private int sampleRate; private int sampleRate;
private long sampleCount; private long sampleCount;
@ -41,10 +47,11 @@ public class Mp3Manager implements MusicManager {
Bitstream bitstream; Bitstream bitstream;
MP3Decoder decoder; MP3Decoder decoder;
OutputBuffer sampleBuffer; OutputBuffer sampleBuffer;
InputStream inputStream;
private byte[] currentByteSet; private byte[] currentByteSet;
private byte[] workset; private byte[] workset;
private int indexHead = -1; private int indexHead = -1;
private RandomAccessFile raf;
private FileHandle file; private FileHandle file;
ReentrantLock lock = new ReentrantLock(); ReentrantLock lock = new ReentrantLock();
@ -71,9 +78,14 @@ public class Mp3Manager implements MusicManager {
lock.unlock(); lock.unlock();
}); });
bitstream = new Bitstream(audioFile.read()); try {
decoder = new MP3Decoder(); raf = new RandomAccessFile(audioFile.file(), "r");
bitstream = new Bitstream(inputStream = Channels.newInputStream(raf.getChannel()));
decoder = new MP3Decoder();
} catch (FileNotFoundException e2) {
e2.printStackTrace();
throw new InvalidParameterException("Error with creating RandomAccessFile.");
}
try { try {
Header header = bitstream.readFrame(); Header header = bitstream.readFrame();
if (header == null) throw new GdxRuntimeException("Empty MP3"); if (header == null) throw new GdxRuntimeException("Empty MP3");
@ -88,15 +100,22 @@ public class Mp3Manager implements MusicManager {
playbackMusic = Gdx.audio.newMusic(audioFile); playbackMusic = Gdx.audio.newMusic(audioFile);
} }
@Override
public void setReadIndexToPlaybackIndex() {
try {
raf.seek((long) (getPositionInSeconds()*(long)sampleRate));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override @Override
public void playbackIndexUpdate() { public void playbackIndexUpdate() {
readIndex = (int) (playbackMusic.getPosition() * sampleRate / readWindowSize); playbackIndex = (int) (playbackMusic.getPosition() * sampleRate / readWindowSize);
} }
@Override @Override
public int getPlaybackIndexPosition() { public int getPlaybackIndexPosition() {
return readIndex; return playbackIndex;
} }
@Override @Override
@ -132,7 +151,7 @@ public class Mp3Manager implements MusicManager {
samples[sid] /= Short.MAX_VALUE+1; samples[sid] /= Short.MAX_VALUE+1;
} }
} }
currentReadWindowIndex++; readWindowIndex++;
return framesRead; return framesRead;
} }
@ -185,8 +204,8 @@ public class Mp3Manager implements MusicManager {
} }
@Override @Override
public int getCurrentReadWindowIndex() { public int getreadWindowIndex() {
return currentReadWindowIndex; return readWindowIndex;
} }
@Override @Override
@ -262,7 +281,8 @@ public class Mp3Manager implements MusicManager {
try { try {
bitstream.close(); bitstream.close();
bitstream = null; bitstream = null;
} catch (BitstreamException e) { inputStream.close();
} catch (BitstreamException | IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }

View File

@ -13,7 +13,7 @@ public interface MusicManager extends Disposable {
public void playbackIndexUpdate(); public void playbackIndexUpdate();
/** /**
* Gets the current position in seconds s * Gets the current position in seconds
* @return the current frame of audio. * @return the current frame of audio.
*/ */
public int getPlaybackIndexPosition(); public int getPlaybackIndexPosition();
@ -54,7 +54,7 @@ public interface MusicManager extends Disposable {
* The current numerical value of the last window read * The current numerical value of the last window read
* @return * @return
*/ */
public int getCurrentReadWindowIndex(); public int getreadWindowIndex();
public void pause(); public void pause();
@ -87,4 +87,8 @@ public interface MusicManager extends Disposable {
* @return the song filehandle. * @return the song filehandle.
*/ */
public FileHandle getMusicFile(); public FileHandle getMusicFile();
/**
*/
public void setReadIndexToPlaybackIndex();
} }

View File

@ -1,6 +1,9 @@
package zero1hd.rhythmbullet.audio; package zero1hd.rhythmbullet.audio;
import java.io.BufferedInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.Channels;
import java.security.InvalidParameterException; import java.security.InvalidParameterException;
import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioFormat;
@ -15,17 +18,20 @@ import zero1hd.rhythmbullet.audio.wavedecoder.WavDecoder;
public class WAVManager implements MusicManager { public class WAVManager implements MusicManager {
private int readWindowSize = 1024; private int readWindowSize = 1024;
private AudioFormat format; private AudioFormat format;
private int readIndex; private int playbackIndex;
private int currentReadWindowIndex; private int readWindowIndex;
private Music playbackMusic; private Music playbackMusic;
WavDecoder decoder; WavDecoder decoder;
private FileHandle file; private FileHandle file;
private String basicSongName; private String basicSongName;
private RandomAccessFile raf;
public WAVManager(FileHandle file) { public WAVManager(FileHandle file) {
this.file = file; this.file = file;
basicSongName = file.name(); basicSongName = file.name();
try { try {
decoder = new WavDecoder(file); raf = new RandomAccessFile(file.file(), "r");
decoder = new WavDecoder(new BufferedInputStream(Channels.newInputStream(raf.getChannel())));
} catch (InvalidParameterException | IOException e) { } catch (InvalidParameterException | IOException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
@ -36,19 +42,28 @@ public class WAVManager implements MusicManager {
@Override @Override
public void playbackIndexUpdate() { public void playbackIndexUpdate() {
readIndex = (int) (playbackMusic.getPosition() * decoder.getSampleRate() / readWindowSize); playbackIndex = (int) (playbackMusic.getPosition() * decoder.getSampleRate() / readWindowSize);
} }
@Override @Override
public int getPlaybackIndexPosition() { public int getPlaybackIndexPosition() {
return readIndex; return playbackIndex;
} }
@Override @Override
public int getReadWindowSize() { public int getReadWindowSize() {
return readWindowSize; return readWindowSize;
} }
@Override
public void setReadIndexToPlaybackIndex() {
try {
raf.seek((long) (getPositionInSeconds()*(long)getSampleRate()));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override @Override
public int readSamples(float[] samples) { public int readSamples(float[] samples) {
int samplesRead = 0; int samplesRead = 0;
@ -59,7 +74,7 @@ public class WAVManager implements MusicManager {
} }
if (samplesRead != 0) { if (samplesRead != 0) {
currentReadWindowIndex++; readWindowIndex++;
} }
return samplesRead; return samplesRead;
} }
@ -87,8 +102,8 @@ public class WAVManager implements MusicManager {
} }
@Override @Override
public int getCurrentReadWindowIndex() { public int getreadWindowIndex() {
return currentReadWindowIndex; return readWindowIndex;
} }
@Override @Override

View File

@ -172,7 +172,7 @@ public class BasicVisualizer extends VisualizerCore {
} }
public void flip() { public void flip() {
flip = flip ? false : true; flip = !flip;
} }
public boolean isFlipped() { public boolean isFlipped() {

View File

@ -17,26 +17,29 @@ public class VisualizerCore implements Disposable {
protected int barCount; protected int barCount;
private boolean calc; private boolean calc;
private ReentrantLock lock; private ReentrantLock lock;
private float updateRate;
private float updateTimer;
public VisualizerCore(int width, int height, int x, int y) { public VisualizerCore(int width, int height, int x, int y) {
this.height = height; this.height = height;
this.width = width; this.width = width;
this.xPos = x; this.xPos = x;
this.yPos = y; this.yPos = y;
updateRate = 1f/30f;
lock = new ReentrantLock(); lock = new ReentrantLock();
} }
public void calculate() { public void calculate(float delta) {
if (mm != null) { if (mm != null && calc && mm.isPlaying()) {
mm.playbackIndexUpdate(); updateTimer += delta;
lock.lock(); if (updateTimer >= updateRate) {
while (calc && mm.isPlaying() && mm.getPlaybackIndexPosition() > mm.getCurrentReadWindowIndex()) { mm.playbackIndexUpdate();
lock.lock();
mm.setReadIndexToPlaybackIndex();
mm.readSamples(audioPCM); mm.readSamples(audioPCM);
if (mm.getPlaybackIndexPosition() == mm.getCurrentReadWindowIndex()) { fft.realForward(audioPCM);
fft.realForward(audioPCM); lock.unlock();
} updateTimer = 0;
} }
lock.unlock();
} }
} }
@ -95,4 +98,12 @@ public class VisualizerCore implements Disposable {
public MusicManager getMm() { public MusicManager getMm() {
return mm; return mm;
} }
public void setUpdateRate(float updateRate) {
this.updateRate = updateRate;
}
public float getUpdateRate() {
return updateRate;
}
} }

View File

@ -1,31 +1,25 @@
package zero1hd.rhythmbullet.audio.wavedecoder; package zero1hd.rhythmbullet.audio.wavedecoder;
import java.io.BufferedInputStream;
import java.io.IOException; import java.io.IOException;
import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem; import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException; import javax.sound.sampled.UnsupportedAudioFileException;
import com.badlogic.gdx.files.FileHandle;
public class WavDecoder { public class WavDecoder {
private FileHandle file;
private int channels; private int channels;
private double sampleRate; private double sampleRate;
private String fileName;
private byte[] buffer; private byte[] buffer;
private AudioInputStream audioInputStream; private AudioInputStream audioInputStream;
public WavDecoder(FileHandle file) throws IOException { public WavDecoder(BufferedInputStream inputStream) throws IOException {
this.file = file;
try { try {
audioInputStream = AudioSystem.getAudioInputStream(file.file()); audioInputStream = AudioSystem.getAudioInputStream(inputStream);
buffer = new byte[audioInputStream.getFormat().getFrameSize()]; buffer = new byte[audioInputStream.getFormat().getFrameSize()];
channels = audioInputStream.getFormat().getChannels(); channels = audioInputStream.getFormat().getChannels();
sampleRate = audioInputStream.getFormat().getSampleRate(); sampleRate = audioInputStream.getFormat().getSampleRate();
fileName = file.name();
} catch (UnsupportedAudioFileException e) { } catch (UnsupportedAudioFileException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -47,14 +41,6 @@ public class WavDecoder {
return audioInputStream.getFrameLength(); return audioInputStream.getFrameLength();
} }
public String getFileName() {
return fileName;
}
public FileHandle getFile() {
return file;
}
public int readSamples(float[] samples) throws IOException { public int readSamples(float[] samples) throws IOException {
int framesRead = 0; int framesRead = 0;
@ -74,6 +60,10 @@ public class WavDecoder {
return framesRead; return framesRead;
} }
public AudioInputStream getAudioInputStream() {
return audioInputStream;
}
public void cleanAndClose() { public void cleanAndClose() {
try { try {
audioInputStream.close(); audioInputStream.close();

View File

@ -40,7 +40,7 @@ public class Visualizer extends Widget implements Disposable {
vis.updatePositionInfo(); vis.updatePositionInfo();
vis.setxPos((getWidth() - vis.getActualWidth())/2f); vis.setxPos((getWidth() - vis.getActualWidth())/2f);
} }
vis.calculate(); vis.calculate(delta);
super.act(delta); super.act(delta);
} }