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);
}
public void modify(float delta) {
public void update(float delta) {
//Averaging bins together
for (int i = 0; i < barCount; i++) {
float barHeight = 0;
@ -104,13 +104,13 @@ public class BasicVisualizer extends VisualizerCore {
@Override
public void setMM(MusicManager mm) {
super.setMM(mm);
maxAvgHeight = 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);
binsPerBar = MathUtils.round((validBins/barCount));
barHeights = new float[barCount];
super.setMM(mm);
}
@Override

View File

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

View File

@ -1,6 +1,7 @@
package zero1hd.rhythmbullet.util;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Music.OnCompletionListener;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Disposable;
@ -64,6 +65,10 @@ public interface MusicManager extends Disposable {
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
* @return whether its done loading
@ -86,4 +91,6 @@ public interface MusicManager extends Disposable {
* @return the amount of windows that have been read.
*/
public int framesRead();
public Music getMusic();
}

View File

@ -265,4 +265,14 @@ public class Mp3Manager implements MusicManager {
public int framesRead() {
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() {
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;
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.backends.lwjgl.audio.OpenALMusic;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.scenes.scene2d.ui.Widget;
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.util.MusicManager;
@ -14,8 +25,20 @@ public class Visualizer extends Widget implements Disposable {
private boolean updatePositioning = true;
private boolean mmSet;
private MusicManager mm;
private ShortBuffer buffer;
private int sourceID;
public Visualizer() {
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
@ -34,18 +57,47 @@ public class Visualizer extends Widget implements Disposable {
mmSet = true;
}
vis.modify(delta);
vis.update(delta);
updateVisualizerProperties();
if (updatePositioning) {
vis.updatePositionInfo();
vis.setxPos((getWidth() - vis.getActualWidth())/2f);
}
if (mmSet) {
setupPCMData();
}
vis.calculate(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) {
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;
mmSet = false;
}