random access files now used to sync visualizer with song (optimization)
This commit is contained in:
		| @@ -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); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user