removed old, unused code; music controls now updated to use new
framework; circular visualizer updated; moved visualizers to core for all platforms and accounted for different platform PCM reading with interface for visualizer in core;
This commit is contained in:
@@ -49,8 +49,6 @@ public class MusicController extends Observable implements OnCompletionListener,
|
||||
music.play();
|
||||
music.setVolume(prefs.getFloat("music vol", 1f));
|
||||
notifyObservers(states.PLAYING);
|
||||
} else {
|
||||
Gdx.app.debug("MusicListController", "failed to begin playing. Load the music!!!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,7 +222,7 @@ public class MusicController extends Observable implements OnCompletionListener,
|
||||
/**
|
||||
* Returns the current music. In no circumstances should this be used to begin playing or it would be playing independent of the controller.
|
||||
* Doing otherwise would mean you are playing the music separately of the controller.
|
||||
* @return
|
||||
* @return the {@link Music} that is currently "loaded" and ready to play.
|
||||
*/
|
||||
public Music getCurrentMusic() {
|
||||
return music;
|
||||
@@ -233,4 +231,11 @@ public class MusicController extends Observable implements OnCompletionListener,
|
||||
public int getCurrentlyPlayingIndex() {
|
||||
return currentlyPlayingIndex;
|
||||
}
|
||||
|
||||
public boolean hasSongLoaded() {
|
||||
if (music != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ import com.badlogic.gdx.utils.Disposable;
|
||||
import zero1hd.rhythmbullet.RhythmBullet;
|
||||
|
||||
public class CircularVisualizer implements Disposable {
|
||||
private PCMSystem pcm;
|
||||
private int centerX, centerY;
|
||||
private int r;
|
||||
private int componentCount = 2 + 1;
|
||||
@@ -27,21 +28,19 @@ public class CircularVisualizer implements Disposable {
|
||||
private float color;
|
||||
private Mesh mesh;
|
||||
private ShaderProgram shader;
|
||||
private Visualizer visualizer;
|
||||
private int barCount = 180;
|
||||
private float barHeightMultiplier = 1.5f;
|
||||
private float[] audioSpectrum;
|
||||
private Camera camera;
|
||||
|
||||
public CircularVisualizer(Visualizer visualizer) {
|
||||
public CircularVisualizer(PCMSystem PCMSystem) {
|
||||
this.pcm = PCMSystem;
|
||||
shader = new ShaderProgram(Gdx.files.internal("shaders/mesh.vsh"), Gdx.files.internal("shaders/mesh.fsh"));
|
||||
if (!shader.isCompiled() || shader.getLog().length() != 0) {
|
||||
Gdx.app.debug("Circular visualizer shader", shader.getLog());
|
||||
Gdx.app.exit();
|
||||
}
|
||||
r = RhythmBullet.pixels_per_unit*RhythmBullet.SPAWN_CIRCLE_RADIUS;
|
||||
|
||||
this.visualizer = visualizer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,112 @@
|
||||
package zero1hd.rhythmbullet.audio.visualizer;
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
|
||||
|
||||
import zero1hd.rhythmbullet.audio.MusicController;
|
||||
|
||||
public class DoubleHorizontalVisualizer {
|
||||
private int width, height, barCount, barWidth, spaceBetweenBars;
|
||||
private int x, y;
|
||||
private float barRate = 0.75f;
|
||||
private ShapeRenderer shapeRenderer;
|
||||
private PCMSystem pcm;
|
||||
private int smoothRange;
|
||||
private int multiplier = 300;
|
||||
private int[] amplitudes;
|
||||
private int[] barHeights;
|
||||
private int binsPerBar;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param barCount amount of bars this visualizer should have.
|
||||
* @param width the width of the visualizer.
|
||||
* @param spacePercentage the percentage of a bar that should be space.
|
||||
*/
|
||||
public DoubleHorizontalVisualizer(int barCount, int width, int height, float spacePercentage, MusicController musicController, PCMSystem PCMSystem) {
|
||||
this.barCount = barCount;
|
||||
this.barWidth = width/barCount;
|
||||
this.spaceBetweenBars = (int) (barWidth * spacePercentage);
|
||||
this.barWidth -= spaceBetweenBars;
|
||||
if (barWidth < 1) throw new IllegalArgumentException("The arguments you passed caused the bar width to be 0.");
|
||||
binsPerBar = (pcm.getWindowSize()/barCount);
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
pcm = PCMSystem;
|
||||
amplitudes = new int[barCount];
|
||||
barHeights = new int[barCount];
|
||||
shapeRenderer = new ShapeRenderer();
|
||||
shapeRenderer.set(ShapeType.Filled);
|
||||
}
|
||||
|
||||
public void act(float delta) {
|
||||
for (int bar = 0; bar < amplitudes.length; bar++) {
|
||||
float normalizedAmplitude = 0;
|
||||
for (int freq = bar*binsPerBar; freq < bar*binsPerBar + binsPerBar; freq++) {
|
||||
normalizedAmplitude += Math.abs(pcm.getFrequencyBins()[freq]);
|
||||
}
|
||||
amplitudes[bar] = (int) (normalizedAmplitude*multiplier);
|
||||
amplitudes[bar] /= binsPerBar;
|
||||
|
||||
barHeights[bar] += Math.max(0, (amplitudes[bar] - barHeights[bar]) * barRate * delta);
|
||||
if (barHeights[bar] > amplitudes[bar]) barHeights[bar] = amplitudes[bar];
|
||||
|
||||
}
|
||||
for (int bar = 1; bar <= barHeights.length; bar++) {
|
||||
int smoothCount = 1;
|
||||
for (int range = 0; range < smoothRange; range++) {
|
||||
if (bar+range < amplitudes.length) {
|
||||
barHeights[bar] += amplitudes[bar+range];
|
||||
smoothCount++;
|
||||
}
|
||||
if (bar-range > 0) {
|
||||
barHeights[bar] += amplitudes[bar-range];
|
||||
smoothCount++;
|
||||
}
|
||||
}
|
||||
barHeights[bar] /= smoothCount;
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(Batch batch, float parentAlpha) {
|
||||
shapeRenderer.begin();
|
||||
shapeRenderer.rect(x, y-2, width, y);
|
||||
shapeRenderer.rect(x, y+height, width, y+height+2);
|
||||
int beginX = x + spaceBetweenBars/2, beginY = y;
|
||||
for (int bar = 0; bar < barCount; bar++) {
|
||||
shapeRenderer.rect(beginX + spaceBetweenBars*bar, beginY+height, beginX+barWidth, beginY+barHeights[bar]+height);
|
||||
shapeRenderer.rect(beginX + spaceBetweenBars*bar, beginY, beginX+barWidth, beginY+barHeights[barHeights.length - 1 - bar]);
|
||||
}
|
||||
shapeRenderer.end();
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public void setPosition(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
}
|
@@ -1,280 +0,0 @@
|
||||
package zero1hd.rhythmbullet.audio.visualizer;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Pixmap.Format;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.graphics.g2d.Sprite;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
|
||||
|
||||
public class HorizontalVisualizer implements Disposable {
|
||||
private Pixmap pixmap;
|
||||
private Texture barTexture;
|
||||
private int barWidth;
|
||||
private int binsPerBar;
|
||||
private int spaceBetweenBars;
|
||||
private Sprite[] bars;
|
||||
private float[] barHeights;
|
||||
private int smoothRange;
|
||||
private float barHeightMultiplier;
|
||||
private float rotation;
|
||||
private Vector2 angleRot;
|
||||
private boolean flip;
|
||||
private Array<MirrorVisualizer> mirrors;
|
||||
private boolean reverse;
|
||||
private float maxAvgHeight;
|
||||
private float currentAvg;
|
||||
private int barCount;
|
||||
private float width, height, x, y;
|
||||
|
||||
private Visualizer visualizer;
|
||||
|
||||
public HorizontalVisualizer(Visualizer visualizer) {
|
||||
super();
|
||||
mirrors = new Array<>();
|
||||
pixmap = new Pixmap(2, 2, Format.RGBA8888);
|
||||
pixmap.setColor(Color.WHITE);
|
||||
pixmap.fill();
|
||||
|
||||
barCount = 68;
|
||||
|
||||
width = Gdx.graphics.getWidth();
|
||||
height = Gdx.graphics.getHeight()/2f;
|
||||
x = 0;
|
||||
y = 0;
|
||||
|
||||
this.visualizer = visualizer;
|
||||
|
||||
smoothRange = 2;
|
||||
angleRot = new Vector2(MathUtils.cosDeg(rotation), MathUtils.sinDeg(rotation));
|
||||
bars = new Sprite[barCount];
|
||||
barHeights = new float[barCount];
|
||||
barTexture = new Texture(pixmap);
|
||||
for (int i = 0; i < bars.length; i++) {
|
||||
bars[i] = new Sprite(barTexture);
|
||||
}
|
||||
|
||||
updatePositionInfo();
|
||||
pixmap.dispose();
|
||||
}
|
||||
|
||||
public void render(Batch batch, float parentAlpha) {
|
||||
if (visualizer.getMM() != null) {
|
||||
for (int i = 0; i < bars.length; i++) {
|
||||
bars[i].draw(batch);
|
||||
for (int j = 0; j < mirrors.size; j++) {
|
||||
mirrors.get(j).render(i, batch, parentAlpha, bars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void update(float delta) {
|
||||
if (visualizer.getMM() != null) {
|
||||
//Averaging bins together
|
||||
for (int i = 0; i < barCount; i++) {
|
||||
float barHeight = 0;
|
||||
for (int j = 0; j < binsPerBar; j++) {
|
||||
barHeight += Math.abs(visualizer.getAudioPCMData()[j+i*binsPerBar +1]);
|
||||
}
|
||||
barHeight /= binsPerBar;
|
||||
barHeight *= barHeightMultiplier;
|
||||
barHeights[i] = barHeight;
|
||||
}
|
||||
currentAvg = 0;
|
||||
for (int i = 0; i < barCount; i++) {
|
||||
int avg = 0;
|
||||
//Averaging the bars
|
||||
for (int range = 0; range < smoothRange; range++) {
|
||||
if (i+range < barCount) {
|
||||
avg += barHeights[i+range];
|
||||
}
|
||||
if (i-range >= 0) {
|
||||
avg += barHeights[i-range];
|
||||
}
|
||||
}
|
||||
avg /= smoothRange*2;
|
||||
barHeights[i] = avg;
|
||||
currentAvg += barHeights[i];
|
||||
if (bars[i].getHeight() > barHeights[i]) {
|
||||
bars[i].setSize(barWidth, bars[i].getHeight() - (15f*delta*(bars[i].getHeight()-barHeights[i])));
|
||||
} else {
|
||||
bars[i].setSize(barWidth, bars[i].getHeight() + (20f*delta*(barHeights[i] - bars[i].getHeight())));
|
||||
}
|
||||
}
|
||||
currentAvg /= barHeights.length;
|
||||
if (currentAvg > maxAvgHeight) {
|
||||
maxAvgHeight = currentAvg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setMM(MusicManager mm) {
|
||||
maxAvgHeight = 0;
|
||||
currentAvg = 0;
|
||||
float validBins = (4200/((mm.getSampleRate()/2)/((mm.getReadWindowSize()/2)+1)));
|
||||
Gdx.app.debug("Visualizer", "valid frequency bins " + validBins);
|
||||
binsPerBar = MathUtils.round((validBins/barCount));
|
||||
barHeights = new float[barCount];
|
||||
visualizer.setMM(mm);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
barTexture.dispose();
|
||||
visualizer.dispose();
|
||||
}
|
||||
|
||||
public void updatePositionInfo() {
|
||||
barHeightMultiplier = height;
|
||||
int barSpace = 0;
|
||||
angleRot.set(MathUtils.cosDeg(rotation), MathUtils.sinDeg(rotation));
|
||||
|
||||
barWidth = MathUtils.round((float) width/(float) barCount);
|
||||
barWidth -= spaceBetweenBars;
|
||||
for (int i = 0; i < bars.length; i++) {
|
||||
barSpace = i*(barWidth+spaceBetweenBars);
|
||||
if (flip) {
|
||||
bars[i].setRotation(rotation+180);
|
||||
} else {
|
||||
bars[i].setRotation(rotation);
|
||||
}
|
||||
if (reverse) {
|
||||
bars[bars.length-i-1].setPosition(x + barSpace*angleRot.x, y + barSpace*angleRot.y);
|
||||
} else {
|
||||
bars[i].setPosition(x + barSpace*angleRot.x, y + barSpace*angleRot.y);
|
||||
}
|
||||
for (int mirrorIndex = 0; mirrorIndex < mirrors.size; mirrorIndex++) {
|
||||
mirrors.get(mirrorIndex).position(i, barWidth, spaceBetweenBars);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public float getActualWidth() {
|
||||
return (barWidth+spaceBetweenBars)*(barCount - 1);
|
||||
}
|
||||
|
||||
public void setColor(Color color) {
|
||||
for (int i = 0; i < bars.length; i++) {
|
||||
bars[i].setColor(color);
|
||||
}
|
||||
for (int i = 0; i < mirrors.size; i++) {
|
||||
mirrors.get(i).setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
public void setColor(float r, float g, float b, float a) {
|
||||
for (int i = 0; i < bars.length; i++) {
|
||||
bars[i].setColor(r, g, b, a);
|
||||
}
|
||||
for (int i = 0; i < mirrors.size; i++) {
|
||||
mirrors.get(i).setColor(r, g, b, a);
|
||||
}
|
||||
}
|
||||
|
||||
public void setRotation(float rotation) {
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
public void flip() {
|
||||
flip = !flip;
|
||||
}
|
||||
|
||||
public boolean isFlipped() {
|
||||
return flip;
|
||||
}
|
||||
|
||||
public void addMirrorVisualizer(MirrorVisualizer mirror) {
|
||||
updatePositionInfo();
|
||||
mirror.setup(bars, x, y, rotation);
|
||||
mirrors.add(mirror);
|
||||
x = (int) (((width - getActualWidth())/2f));
|
||||
}
|
||||
|
||||
public void removeMirrorVisualizer(MirrorVisualizer mirror) {
|
||||
mirrors.removeValue(mirror, true);
|
||||
}
|
||||
|
||||
public void setSpaceBetweenBars(int spaceBetweenBars) {
|
||||
this.spaceBetweenBars = spaceBetweenBars;
|
||||
}
|
||||
|
||||
public int getBarWidth() {
|
||||
return barWidth;
|
||||
}
|
||||
|
||||
public void reverse() {
|
||||
reverse = reverse ? false : true;
|
||||
}
|
||||
|
||||
public boolean isReversed() {
|
||||
return reverse;
|
||||
}
|
||||
|
||||
public Sprite[] getBars() {
|
||||
return bars;
|
||||
}
|
||||
|
||||
public float getCurrentAvg() {
|
||||
return currentAvg;
|
||||
}
|
||||
|
||||
public float getMaxAvgHeight() {
|
||||
return maxAvgHeight;
|
||||
}
|
||||
|
||||
public int getSpaceBetweenBars() {
|
||||
return spaceBetweenBars;
|
||||
}
|
||||
|
||||
public void setX(float x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setY(float y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setWidth(float width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setHeight(float height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public float getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void calcPCMData() {
|
||||
visualizer.calcPCMData();
|
||||
}
|
||||
|
||||
public void calculate() {
|
||||
visualizer.fft();
|
||||
}
|
||||
|
||||
public Visualizer getVisualizer() {
|
||||
return visualizer;
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
package zero1hd.rhythmbullet.audio.visualizer;
|
||||
|
||||
public interface PCMSystem {
|
||||
|
||||
float[] getFrequencyBins();
|
||||
|
||||
int getWindowSize();
|
||||
|
||||
}
|
@@ -1,106 +0,0 @@
|
||||
package zero1hd.rhythmbullet.game;
|
||||
|
||||
import zero1hd.rhythmbullet.audio.MusicManager;
|
||||
import zero1hd.rhythmbullet.entity.Entity;
|
||||
import zero1hd.rhythmbullet.entity.EntityFrame;
|
||||
import zero1hd.rhythmbullet.entity.coordinator.Coordinator;
|
||||
import zero1hd.rhythmbullet.entity.coordinator.CoordinatorFrame;
|
||||
|
||||
public class GamePlayMap {
|
||||
private MusicManager musicData;
|
||||
private MapWindowData[] spawnList;
|
||||
private boolean building;
|
||||
private int index;
|
||||
|
||||
private byte[] hudType;
|
||||
/**
|
||||
* GamePlayMap is what the game area will use to generate entities and judge current audio data
|
||||
* @param audioData audio data
|
||||
*/
|
||||
public GamePlayMap(MusicManager audioData, int totalWindows) {
|
||||
this.musicData = audioData;
|
||||
spawnList = new MapWindowData[totalWindows];
|
||||
hudType = new byte[totalWindows];
|
||||
}
|
||||
|
||||
public int setIndex(int index) {
|
||||
int previousIndex = this.index;
|
||||
if (index < 0) {
|
||||
this.index = 0;
|
||||
} else if (index >= spawnList.length) {
|
||||
toHead();
|
||||
} else {
|
||||
this.index = index;
|
||||
}
|
||||
return previousIndex;
|
||||
}
|
||||
|
||||
public void setHUDType(byte data) {
|
||||
hudType[index] = data;
|
||||
}
|
||||
|
||||
public byte[] getHudType() {
|
||||
return hudType;
|
||||
}
|
||||
|
||||
public EntitySpawnInfo addEntity(EntityFrame<? extends Entity> entityType, CoordinatorFrame<? extends Coordinator> coordinator) {
|
||||
if (building) {
|
||||
if (spawnList[index] == null) {
|
||||
spawnList[index] = new MapWindowData();
|
||||
}
|
||||
EntitySpawnInfo esi = new EntitySpawnInfo(entityType, coordinator);
|
||||
spawnList[index].addEntity(esi);
|
||||
return esi;
|
||||
} else {
|
||||
throw new IllegalStateException("Stupid, you need to call begin building first first.");
|
||||
}
|
||||
}
|
||||
|
||||
public void nextWindowData() {
|
||||
if (building) {
|
||||
index++;
|
||||
} else {
|
||||
throw new IllegalStateException("Stupid, you need to call begin building first first.");
|
||||
}
|
||||
}
|
||||
|
||||
public void toHead() {
|
||||
index = spawnList.length-1;
|
||||
}
|
||||
|
||||
public MusicManager getMusicData() {
|
||||
return musicData;
|
||||
}
|
||||
|
||||
public void beginBuild() {
|
||||
if (!building) {
|
||||
index = 0;
|
||||
building = true;
|
||||
} else {
|
||||
throw new IllegalStateException("Excuse me, but your already building...");
|
||||
}
|
||||
}
|
||||
|
||||
public void endBuild() {
|
||||
if (building) {
|
||||
index = 0;
|
||||
building = false;
|
||||
} else {
|
||||
throw new IllegalStateException("Nothings being built...");
|
||||
}
|
||||
}
|
||||
|
||||
public MapWindowData getCurrentWindowBasedOnIndex() {
|
||||
if (index != musicData.getPlaybackIndexPosition()) {
|
||||
index = musicData.getPlaybackIndexPosition();
|
||||
if (index < spawnList.length) {
|
||||
return spawnList[index];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user