visualizer now directly grabs data from openal.. slightly less synched for better efficiency?

This commit is contained in:
Harrison Deng 2018-01-09 23:22:59 -06:00
parent b6da79adc2
commit 7b8f442f98
6 changed files with 93 additions and 26 deletions

View File

@ -64,7 +64,7 @@ public class BasicVisualizer extends VisualizerCore {
super.render(batch, parentAlpha); super.render(batch, parentAlpha);
} }
public void modify(float delta) { public void update(float delta) {
//Averaging bins together //Averaging bins together
for (int i = 0; i < barCount; i++) { for (int i = 0; i < barCount; i++) {
float barHeight = 0; float barHeight = 0;
@ -104,13 +104,13 @@ public class BasicVisualizer extends VisualizerCore {
@Override @Override
public void setMM(MusicManager mm) { public void setMM(MusicManager mm) {
super.setMM(mm);
maxAvgHeight = 0; maxAvgHeight = 0;
currentAvg = 0; currentAvg = 0;
float validBins = (5500/((mm.getSampleRate()/2)/((audioPCM.length/2)+1))); float validBins = (5500/((mm.getSampleRate()/2)/((mm.getReadWindowSize()/2)+1)));
Gdx.app.debug("Visualizer", "valid frequency bins " + validBins); Gdx.app.debug("Visualizer", "valid frequency bins " + validBins);
binsPerBar = MathUtils.round((validBins/barCount)); binsPerBar = MathUtils.round((validBins/barCount));
barHeights = new float[barCount]; barHeights = new float[barCount];
super.setMM(mm);
} }
@Override @Override

View File

@ -11,44 +11,36 @@ import zero1hd.rhythmbullet.util.MusicManager;
public class VisualizerCore implements Disposable { public class VisualizerCore implements Disposable {
protected MusicManager mm; protected MusicManager mm;
private FloatFFT_1D fft; private FloatFFT_1D fft;
float[] audioPCM;
protected float width, height; protected float width, height;
protected float xPos, yPos; protected float xPos, yPos;
protected int barCount; protected int barCount;
private boolean calc; private boolean calc;
private ReentrantLock lock; private ReentrantLock lock;
private float updateRate; protected float[] audioPCM;
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/60f;
lock = new ReentrantLock(); lock = new ReentrantLock();
} }
public void calculate(float delta) { public void calculate(float delta) {
if (mm != null && calc && mm.isPlaying()) { if (mm != null && calc && mm.isPlaying()) {
updateTimer += delta;
if (updateTimer >= updateRate) {
//TODO use current buffer being played
lock.lock(); lock.lock();
mm.readSamples(audioPCM);
fft.realForward(audioPCM); fft.realForward(audioPCM);
lock.unlock(); lock.unlock();
updateTimer = 0;
}
} }
} }
public void setMM(MusicManager mm) { public void setMM(MusicManager mm) {
lock.lock(); lock.lock();
if (audioPCM == null || audioPCM.length != mm.getReadWindowSize()) {
calc = false; calc = false;
if (audioPCM == null || audioPCM.length != mm.getReadWindowSize()) {
audioPCM = new float[mm.getReadWindowSize()];
fft = new FloatFFT_1D(mm.getReadWindowSize()); fft = new FloatFFT_1D(mm.getReadWindowSize());
} }
audioPCM = new float[mm.getReadWindowSize()];
this.mm = mm; this.mm = mm;
calc = true; calc = true;
lock.unlock(); lock.unlock();
@ -57,7 +49,7 @@ public class VisualizerCore implements Disposable {
public void render(Batch batch, float parentAlpha) { public void render(Batch batch, float parentAlpha) {
} }
public void modify(float delta) { public void update(float delta) {
} }
@Override @Override
@ -98,11 +90,7 @@ public class VisualizerCore implements Disposable {
return mm; return mm;
} }
public void setUpdateRate(float updateRate) { public float[] getAudioPCM() {
this.updateRate = updateRate; return audioPCM;
}
public float getUpdateRate() {
return updateRate;
} }
} }

View File

@ -1,6 +1,7 @@
package zero1hd.rhythmbullet.util; package zero1hd.rhythmbullet.util;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Music.OnCompletionListener; import com.badlogic.gdx.audio.Music.OnCompletionListener;
import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Disposable; import com.badlogic.gdx.utils.Disposable;
@ -64,6 +65,10 @@ public interface MusicManager extends Disposable {
public void setVolume(float percent); public void setVolume(float percent);
/**
* @return the amount of channels this audio file has.
*/
public int getChannelCount();
/** /**
* If the the properties of the song are done loading * If the the properties of the song are done loading
* @return whether its done loading * @return whether its done loading
@ -86,4 +91,6 @@ public interface MusicManager extends Disposable {
* @return the amount of windows that have been read. * @return the amount of windows that have been read.
*/ */
public int framesRead(); public int framesRead();
public Music getMusic();
} }

View File

@ -265,4 +265,14 @@ public class Mp3Manager implements MusicManager {
public int framesRead() { public int framesRead() {
return readIndex; return readIndex;
} }
@Override
public int getChannelCount() {
return channels;
}
@Override
public Music getMusic() {
return playbackMusic;
}
} }

View File

@ -141,4 +141,14 @@ public class WAVManager implements MusicManager {
public int framesRead() { public int framesRead() {
return readIndex; return readIndex;
} }
@Override
public int getChannelCount() {
return d.getChannels();
}
@Override
public Music getMusic() {
return music;
}
} }

View File

@ -1,10 +1,21 @@
package zero1hd.rhythmbullet.desktop.graphics.ui.components; package zero1hd.rhythmbullet.desktop.graphics.ui.components;
import static org.lwjgl.openal.AL10.*;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import org.lwjgl.openal.AL11;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.lwjgl.audio.OpenALMusic;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.scenes.scene2d.ui.Widget; import com.badlogic.gdx.scenes.scene2d.ui.Widget;
import com.badlogic.gdx.utils.Disposable; import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.reflect.ClassReflection;
import com.badlogic.gdx.utils.reflect.Field;
import com.badlogic.gdx.utils.reflect.ReflectionException;
import zero1hd.rhythmbullet.audio.visualizer.BasicVisualizer; import zero1hd.rhythmbullet.audio.visualizer.BasicVisualizer;
import zero1hd.rhythmbullet.util.MusicManager; import zero1hd.rhythmbullet.util.MusicManager;
@ -14,8 +25,20 @@ public class Visualizer extends Widget implements Disposable {
private boolean updatePositioning = true; private boolean updatePositioning = true;
private boolean mmSet; private boolean mmSet;
private MusicManager mm; private MusicManager mm;
private ShortBuffer buffer;
private int sourceID;
public Visualizer() { public Visualizer() {
vis = new BasicVisualizer(); vis = new BasicVisualizer();
try {
Field tempBufferField = ClassReflection.getDeclaredField(OpenALMusic.class, "tempBuffer");
tempBufferField.setAccessible(true);
buffer = ((ByteBuffer) tempBufferField.get(null)).asShortBuffer();
} catch (IllegalArgumentException | SecurityException | ReflectionException e) {
e.printStackTrace();
Gdx.app.debug("Visualizer reflection", "Failed attempt at retrieving tempBuffer field.");
Gdx.app.exit();
}
} }
@Override @Override
@ -34,18 +57,47 @@ public class Visualizer extends Widget implements Disposable {
mmSet = true; mmSet = true;
} }
vis.modify(delta); vis.update(delta);
updateVisualizerProperties(); updateVisualizerProperties();
if (updatePositioning) { if (updatePositioning) {
vis.updatePositionInfo(); vis.updatePositionInfo();
vis.setxPos((getWidth() - vis.getActualWidth())/2f); vis.setxPos((getWidth() - vis.getActualWidth())/2f);
} }
if (mmSet) {
setupPCMData();
}
vis.calculate(delta); vis.calculate(delta);
super.act(delta); super.act(delta);
} }
public void setupPCMData() {
short chanVal;
int pos = (int) ((alGetSourcef(sourceID, AL11.AL_SAMPLE_OFFSET)-4));
try {
buffer.position((int) Math.max(0, pos));
} catch (IllegalArgumentException outOfBounds) {
System.out.println(outOfBounds);
}
for (int sid = 0; sid < vis.getAudioPCM().length && sid < buffer.remaining(); sid++) {
for (int channel = 0; channel < mm.getChannelCount(); channel ++) {
if (vis.getAudioPCM()[sid] < (chanVal = buffer.get())) {
vis.getAudioPCM()[sid] = chanVal;
}
}
vis.getAudioPCM()[sid] /= Short.MAX_VALUE+1;
}
}
public void setMM(MusicManager mm) { public void setMM(MusicManager mm) {
try {
Field sourceIDField = ClassReflection.getDeclaredField(OpenALMusic.class, "sourceID");
sourceIDField.setAccessible(true);
sourceID = (int) sourceIDField.get(mm.getMusic());
} catch (ReflectionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.mm = mm; this.mm = mm;
mmSet = false; mmSet = false;
} }