random access files now used to sync visualizer with song (optimization)
This commit is contained in:
parent
8023987148
commit
51ce146611
@ -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 {
|
||||||
|
raf = new RandomAccessFile(audioFile.file(), "r");
|
||||||
|
bitstream = new Bitstream(inputStream = Channels.newInputStream(raf.getChannel()));
|
||||||
decoder = new MP3Decoder();
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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,12 +42,12 @@ 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
|
||||||
@ -49,6 +55,15 @@ public class WAVManager implements MusicManager {
|
|||||||
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
|
||||||
|
@ -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() {
|
||||||
|
@ -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()) {
|
||||||
|
updateTimer += delta;
|
||||||
|
if (updateTimer >= updateRate) {
|
||||||
mm.playbackIndexUpdate();
|
mm.playbackIndexUpdate();
|
||||||
lock.lock();
|
lock.lock();
|
||||||
while (calc && mm.isPlaying() && mm.getPlaybackIndexPosition() > mm.getCurrentReadWindowIndex()) {
|
mm.setReadIndexToPlaybackIndex();
|
||||||
mm.readSamples(audioPCM);
|
mm.readSamples(audioPCM);
|
||||||
if (mm.getPlaybackIndexPosition() == mm.getCurrentReadWindowIndex()) {
|
|
||||||
fft.realForward(audioPCM);
|
fft.realForward(audioPCM);
|
||||||
}
|
|
||||||
}
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
updateTimer = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user