Prototyping visualizer as well as design scheme

This commit is contained in:
Harrison Deng 2017-09-06 23:31:10 -05:00
parent c45551f1d2
commit 22ab329e19
21 changed files with 367 additions and 295 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -19,7 +19,6 @@ import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator; import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter; import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.scenes.scene2d.ui.Button.ButtonStyle;
import com.badlogic.gdx.scenes.scene2d.ui.CheckBox.CheckBoxStyle; import com.badlogic.gdx.scenes.scene2d.ui.CheckBox.CheckBoxStyle;
import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle; import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle;
import com.badlogic.gdx.scenes.scene2d.ui.List.ListStyle; import com.badlogic.gdx.scenes.scene2d.ui.List.ListStyle;
@ -53,7 +52,6 @@ public class RhythmBullet extends Game {
private Preferences prefs; private Preferences prefs;
private RoundingResolutionHandler rRHandler; private RoundingResolutionHandler rRHandler;
@Override @Override
public void create() { public void create() {
Gdx.app.setLogLevel(Application.LOG_DEBUG); Gdx.app.setLogLevel(Application.LOG_DEBUG);
@ -113,7 +111,7 @@ public class RhythmBullet extends Game {
public void dispose() { public void dispose() {
Gdx.app.debug("Core", "disposing..."); Gdx.app.debug("Core", "disposing...");
if (initComplete) { if (initComplete) {
// skinAtlas.dispose(); skinAtlas.dispose();
getDefaultSkin().dispose(); getDefaultSkin().dispose();
default_fontGenerator.dispose(); default_fontGenerator.dispose();
darktech_ldr_fontGenerator.dispose(); darktech_ldr_fontGenerator.dispose();
@ -252,11 +250,6 @@ public class RhythmBullet extends Game {
vertSlider.knob = getDefaultSkin().getDrawable("vertical-slider-knob"); vertSlider.knob = getDefaultSkin().getDrawable("vertical-slider-knob");
getDefaultSkin().add("default-vertical", vertSlider); getDefaultSkin().add("default-vertical", vertSlider);
ButtonStyle infoButton = new ButtonStyle();
infoButton.up = getDefaultSkin().getDrawable("holo-pane");
infoButton.down = getDefaultSkin().getDrawable("holo-pane-down");
getDefaultSkin().add("info-button", infoButton);
LabelStyle defaultLabel = new LabelStyle(); LabelStyle defaultLabel = new LabelStyle();
defaultLabel.font = getDefaultSkin().getFont("default-font"); defaultLabel.font = getDefaultSkin().getFont("default-font");
defaultLabel.fontColor = getDefaultSkin().getColor("default"); defaultLabel.fontColor = getDefaultSkin().getColor("default");

View File

@ -1,15 +0,0 @@
package zero1hd.rhythmbullet.audio;
import com.badlogic.gdx.files.FileHandle;
public class Audio {
public static CoreMusicInfo getAudioData(FileHandle file) {
if (file.extension().equalsIgnoreCase("wav")) {
return new WavAudioData(file);
} else if (file.extension().equalsIgnoreCase("mp3")) {
return new Mp3AudioData(file);
}
return null;
}
}

View File

@ -18,7 +18,7 @@ import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.utils.Disposable; import com.badlogic.gdx.utils.Disposable;
public class AudioInfo implements Disposable { public class SongInfo implements Disposable {
private long durationInSeconds; private long durationInSeconds;
private String songName; private String songName;
private Texture albumCover; private Texture albumCover;
@ -28,7 +28,17 @@ public class AudioInfo implements Disposable {
private byte[] albumWorkBytes; private byte[] albumWorkBytes;
private boolean invalidMusic; private boolean invalidMusic;
public AudioInfo(FileHandle musicFile, Preferences musicData) { private boolean containsInfo;
private FileHandle musicFile;
private Preferences musicAnnotation;
public SongInfo(FileHandle musicFile, Preferences musicData) {
this.musicFile = musicFile;
this.musicAnnotation = musicData;
}
public void loadInfo() {
if (musicFile.extension().toLowerCase().equals("mp3")) { if (musicFile.extension().toLowerCase().equals("mp3")) {
MP3File mp3File; MP3File mp3File;
try { try {
@ -68,8 +78,8 @@ public class AudioInfo implements Disposable {
songName = musicFile.nameWithoutExtension(); songName = musicFile.nameWithoutExtension();
} }
previousTop = musicData.getInteger(songName + ":previous top", -1); previousTop = musicAnnotation.getInteger(songName + ":previous top", -1);
ratedDifficulty = musicData.getInteger(songName + ":difficulty", -1); ratedDifficulty = musicAnnotation.getInteger(songName + ":difficulty", -1);
if (author == null || author.isEmpty()) { if (author == null || author.isEmpty()) {
author = "N/A"; author = "N/A";
@ -119,4 +129,18 @@ public class AudioInfo implements Disposable {
albumCover.dispose(); albumCover.dispose();
} }
/**
* tells this song info that it does contain information
*/
public void doesContainsInformation() {
containsInfo = true;
}
/**
* Asks if this contains information.
* @return whether this contains data
*/
public boolean hasInformation() {
return containsInfo;
}
} }

View File

@ -0,0 +1,48 @@
package zero1hd.rhythmbullet.audio;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array;
public class SongList {
private Array<FileHandle> songList;
private String searchPath;
public SongList() {
songList = new Array<>();
}
public void refresh() {
songList.addAll(Gdx.files.absolute(searchPath).list((dir, name) -> {
if (name.endsWith("mp3") || name.endsWith("wav")) {
return true;
}
return false;
}));
}
public void setSearchPath(String searchPath) {
this.searchPath = searchPath;
}
public CoreMusicInfo getAudioData(FileHandle file) {
if (file.extension().equalsIgnoreCase("wav")) {
return new WavAudioData(file);
} else if (file.extension().equalsIgnoreCase("mp3")) {
return new Mp3AudioData(file);
}
return null;
}
public CoreMusicInfo getMusicInfoFromIndex(int index) {
return getAudioData(songList.get(index));
}
public Array<FileHandle> getSongList() {
return songList;
}
public int getAmountOfSongs() {
return songList.size;
}
}

View File

@ -9,7 +9,7 @@ import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music; import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.files.FileHandle;
import zero1hd.wavedecoder.WavDecoder; import zero1hd.rhythmbullet.audio.wavedecoder.WavDecoder;
public class WavAudioData implements CoreMusicInfo { public class WavAudioData implements CoreMusicInfo {
private int readWindowSize = 1024; private int readWindowSize = 1024;

View File

@ -0,0 +1,59 @@
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 zero1hd.rhythmbullet.audio.CoreMusicInfo;
public class HorizontalVisualizer extends VisualizerCore {
private Pixmap pixmap;
private Texture bar;
private int barWidth;
private int binsPerBar;
private int spaceBetweenBars;
public HorizontalVisualizer() {
super(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()/2, 0, 0);
pixmap = new Pixmap(2, 2, Format.RGBA8888);
pixmap.setColor(Color.GRAY);
pixmap.fill();
bar = new Texture(pixmap);
pixmap.dispose();
barCount = 64;
barWidth = width/barCount;
}
@Override
public void render(Batch batch, float parentAlpha) {
if (cmi != null) {
for (int i = 0; i < barCount; i++) {
int currentBinAvg = 0;
for (int j = i; j < binsPerBar; j++) {
currentBinAvg += audioPCM[j];
}
currentBinAvg /= binsPerBar;
batch.draw(bar, xPos + i*(barWidth+spaceBetweenBars), yPos, barWidth, currentBinAvg*height);
}
}
super.render(batch, parentAlpha);
}
@Override
public void setCmi(CoreMusicInfo cmi) {
binsPerBar = audioPCM.length/barCount;
super.setCmi(cmi);
}
@Override
public void dispose() {
bar.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,49 @@
package zero1hd.rhythmbullet.audio.visualizer;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.utils.Disposable;
import edu.emory.mathcs.jtransforms.fft.FloatFFT_1D;
import zero1hd.rhythmbullet.audio.CoreMusicInfo;
public class VisualizerCore implements Disposable {
protected CoreMusicInfo cmi;
private FloatFFT_1D fft;
float[] audioPCM;
protected int width, height;
protected int xPos, yPos;
protected int barCount;
public VisualizerCore(int width, int height, int x, int y) {
}
public void update() {
if (cmi != null) {
if (cmi.getPlaybackIndexPosition() > cmi.getCurrentReadWindowIndex()) {
cmi.readSamples(audioPCM);
fft.realForward(audioPCM);
Gdx.app.debug("Visualizer", "Skipping a frame to catch up to music.");
} else {
Gdx.app.debug("Visualizer", "Not reading so music can catch up.");
}
}
}
public void setCmi(CoreMusicInfo cmi) {
this.cmi = cmi;
fft = new FloatFFT_1D(cmi.getReadWindowSize());
audioPCM = new float[cmi.getReadWindowSize()];
}
public void render(Batch batch, float parentAlpha) {
}
@Override
public void dispose() {
// TODO Auto-generated method stub
}
}

View File

@ -1,4 +1,4 @@
package zero1hd.wavedecoder; package zero1hd.rhythmbullet.audio.wavedecoder;
import java.io.IOException; import java.io.IOException;

View File

@ -3,6 +3,7 @@ package zero1hd.rhythmbullet.screens;
import com.badlogic.gdx.Preferences; import com.badlogic.gdx.Preferences;
import zero1hd.rhythmbullet.RhythmBullet; import zero1hd.rhythmbullet.RhythmBullet;
import zero1hd.rhythmbullet.audio.SongList;
import zero1hd.rhythmbullet.stages.CreativeHUD; import zero1hd.rhythmbullet.stages.CreativeHUD;
public class CreativeScreen extends GameScreen { public class CreativeScreen extends GameScreen {
@ -10,9 +11,9 @@ public class CreativeScreen extends GameScreen {
Preferences prefs; Preferences prefs;
public CreativeScreen(RhythmBullet core, MainMenu mainMenu) { public CreativeScreen(RhythmBullet core, MainMenu mainMenu, SongList sl) {
super(core, mainMenu); super(core, mainMenu);
chud = new CreativeHUD(core, mainMenu, gameArea, gameHUD); chud = new CreativeHUD(core, mainMenu, gameArea, gameHUD, sl);
inputs.addProcessor(chud); inputs.addProcessor(chud);
this.prefs = core.getPrefs(); this.prefs = core.getPrefs();

View File

@ -12,6 +12,7 @@ import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.viewport.ScreenViewport; import com.badlogic.gdx.utils.viewport.ScreenViewport;
import zero1hd.rhythmbullet.RhythmBullet; import zero1hd.rhythmbullet.RhythmBullet;
import zero1hd.rhythmbullet.audio.SongList;
import zero1hd.rhythmbullet.ui.pages.CreditsPage; import zero1hd.rhythmbullet.ui.pages.CreditsPage;
import zero1hd.rhythmbullet.ui.pages.MainPage; import zero1hd.rhythmbullet.ui.pages.MainPage;
import zero1hd.rhythmbullet.ui.pages.MoreOptionsPage; import zero1hd.rhythmbullet.ui.pages.MoreOptionsPage;
@ -29,12 +30,16 @@ public class MainMenu extends ScreenAdapter implements TransitionAdapter {
private RhythmBullet core; private RhythmBullet core;
private SongList songList;
private float lerpAlpha; private float lerpAlpha;
public MainMenu(final RhythmBullet core) { public MainMenu(final RhythmBullet core) {
this.core = core; this.core = core;
stage = new Stage(new ScreenViewport()); stage = new Stage(new ScreenViewport());
targetPosition = new Vector3(stage.getCamera().position); targetPosition = new Vector3(stage.getCamera().position);
songList = new SongList();
songList.setSearchPath(core.getPrefs().getString("music dir"));
songList.refresh();
postTransition(); postTransition();
} }
@ -49,14 +54,14 @@ public class MainMenu extends ScreenAdapter implements TransitionAdapter {
@Override @Override
public void postTransition() { public void postTransition() {
mainPage = new MainPage(core, targetPosition); mainPage = new MainPage(core, targetPosition, songList);
mainPage.setPosition(0, 0); mainPage.setPosition(0, 0);
stage.addActor(mainPage); stage.addActor(mainPage);
//End main menu //End main menu
moreOptionsPage = new MoreOptionsPage(core, targetPosition); moreOptionsPage = new MoreOptionsPage(core, targetPosition);
optionsPage = new OptionsPage(core, targetPosition, moreOptionsPage); optionsPage = new OptionsPage(core, targetPosition, moreOptionsPage, songList);
optionsPage.setPosition(Gdx.graphics.getWidth(), 0); optionsPage.setPosition(Gdx.graphics.getWidth(), 0);
stage.addActor(optionsPage); stage.addActor(optionsPage);
@ -119,13 +124,11 @@ public class MainMenu extends ScreenAdapter implements TransitionAdapter {
@Override @Override
public void render(float delta) { public void render(float delta) {
Gdx.gl.glClearColor(1f, 1f, 1f, 1f); Gdx.gl.glClearColor(0f, 0f, 0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(); stage.act();
stage.draw(); stage.draw();
if (stage.getCamera().position.x != targetPosition.x || stage.getCamera().position.y != targetPosition.y) { if (stage.getCamera().position.x != targetPosition.x || stage.getCamera().position.y != targetPosition.y) {
stage.getCamera().position.lerp(targetPosition, lerpAlpha); stage.getCamera().position.lerp(targetPosition, lerpAlpha);
} }

View File

@ -8,14 +8,14 @@ import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.utils.viewport.ScreenViewport; import com.badlogic.gdx.utils.viewport.ScreenViewport;
import zero1hd.rhythmbullet.RhythmBullet; import zero1hd.rhythmbullet.RhythmBullet;
import zero1hd.rhythmbullet.audio.Audio; import zero1hd.rhythmbullet.audio.SongList;
import zero1hd.rhythmbullet.ui.pages.AnalyzePage; import zero1hd.rhythmbullet.ui.pages.AnalyzePage;
import zero1hd.rhythmbullet.ui.pages.MusicSelectionPage; import zero1hd.rhythmbullet.ui.pages.MusicSelectionPage;
import zero1hd.rhythmbullet.util.MiniEvents; import zero1hd.rhythmbullet.util.MiniEvents;
import zero1hd.rhythmbullet.util.MiniListener; import zero1hd.rhythmbullet.util.MiniListener;
import zero1hd.rhythmbullet.util.TransitionAdapter; import zero1hd.rhythmbullet.util.TransitionAdapter;
@Deprecated
public class PreGameScreen extends ScreenAdapter implements TransitionAdapter, MiniListener { public class PreGameScreen extends ScreenAdapter implements TransitionAdapter, MiniListener {
Stage stage; Stage stage;
@ -23,11 +23,13 @@ public class PreGameScreen extends ScreenAdapter implements TransitionAdapter, M
public AnalyzePage ap; public AnalyzePage ap;
private Vector3 cameraPos; private Vector3 cameraPos;
private RhythmBullet core; private RhythmBullet core;
private SongList songList;
public PreGameScreen(RhythmBullet core) { public PreGameScreen(RhythmBullet core, SongList songList) {
stage = new Stage(new ScreenViewport()); stage = new Stage(new ScreenViewport());
cameraPos = new Vector3(stage.getCamera().position); cameraPos = new Vector3(stage.getCamera().position);
this.core = core; this.core = core;
this.songList = songList;
postTransition(); postTransition();
} }
@ -62,7 +64,7 @@ public class PreGameScreen extends ScreenAdapter implements TransitionAdapter, M
switch (ID) { switch (ID) {
case MUSIC_SELECTED: case MUSIC_SELECTED:
cameraPos.x = 1.5f*Gdx.graphics.getWidth(); cameraPos.x = 1.5f*Gdx.graphics.getWidth();
ap.setSong(Audio.getAudioData(ms.getSelectedMusic()), ms.getSelectedMusicInfo(), this); ap.setSong(songList.getAudioData(ms.getSelectedMusic()), ms.getSelectedMusicInfo(), this);
break; break;
case BACK: case BACK:
if (cameraPos.x == 1.5f*Gdx.graphics.getWidth()) { if (cameraPos.x == 1.5f*Gdx.graphics.getWidth()) {
@ -85,9 +87,8 @@ public class PreGameScreen extends ScreenAdapter implements TransitionAdapter, M
@Override @Override
public void postTransition() { public void postTransition() {
ms = new MusicSelectionPage(core); ms = new MusicSelectionPage(core.getDefaultSkin(), songList, core.getAssetManager());
ms.miniSender.addListener(this); ms.miniSender.addListener(this);
ms.beginMusicSearch();
stage.addActor(ms); stage.addActor(ms);
ap = new AnalyzePage(core); ap = new AnalyzePage(core);

View File

@ -16,6 +16,7 @@ import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import zero1hd.rhythmbullet.RhythmBullet; import zero1hd.rhythmbullet.RhythmBullet;
import zero1hd.rhythmbullet.audio.AudioAnalyzer; import zero1hd.rhythmbullet.audio.AudioAnalyzer;
import zero1hd.rhythmbullet.audio.AudioDataPackage; import zero1hd.rhythmbullet.audio.AudioDataPackage;
import zero1hd.rhythmbullet.audio.SongList;
import zero1hd.rhythmbullet.audio.map.RhythmMapAlgorithm; import zero1hd.rhythmbullet.audio.map.RhythmMapAlgorithm;
import zero1hd.rhythmbullet.screens.MainMenu; import zero1hd.rhythmbullet.screens.MainMenu;
import zero1hd.rhythmbullet.ui.builders.AudioGraph; import zero1hd.rhythmbullet.ui.builders.AudioGraph;
@ -46,11 +47,11 @@ public class CreativeHUD extends Stage implements MiniListener {
GamePlayArea gpa; GamePlayArea gpa;
GameHUD ghud; GameHUD ghud;
public CreativeHUD(final RhythmBullet core, final MainMenu mainMenu, final GamePlayArea gpa, GameHUD ghud) { public CreativeHUD(final RhythmBullet core, final MainMenu mainMenu, final GamePlayArea gpa, GameHUD ghud, SongList sl) {
this.gpa = gpa; this.gpa = gpa;
this.ghud = ghud; this.ghud = ghud;
musicSelector = new MusicSelector("Select Audio File", core.getDefaultSkin(), core.getPrefs().getString("music dir"), "default"); musicSelector = new MusicSelector("Select Audio File", core.getDefaultSkin(), core.getPrefs().getString("music dir"), sl);
musicSelector.miniSender.addListener(this); musicSelector.miniSender.addListener(this);
musicSelector.refresh(); musicSelector.refresh();

View File

@ -2,107 +2,95 @@ package zero1hd.rhythmbullet.ui.builders;
import com.badlogic.gdx.Preferences; import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.scenes.scene2d.ui.Image; import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.scenes.scene2d.ui.Widget;
import com.badlogic.gdx.utils.Disposable; import com.badlogic.gdx.utils.Disposable;
import zero1hd.rhythmbullet.audio.AudioInfo; import zero1hd.rhythmbullet.audio.SongInfo;
public class MusicSelectable extends Button implements Disposable { public class MusicSelectable extends Widget implements Disposable {
private Table table;
private Image imageIcon; private Image imageIcon;
private ScrollText displayName; private ScrollText displayName;
private Label runTime; private Label durationLabel;
private Label authorLabel; private Label authorLabel;
private Label previousTopLabel;
private Label ratedDifficultyLabel;
private Skin skin;
private FileHandle musicFile; private FileHandle musicFile;
private Texture defaultAlbumCover; private Texture albumCover;
AudioInfo audioInfo; private SongInfo songInfo;
public MusicSelectable(FileHandle musicFile, Preferences musicData, final Skin skin, Texture defaultAlbumC) { private boolean selected;
super(skin, "info-button");
this.skin = skin; public MusicSelectable(FileHandle musicFile, Preferences musicAnnotation, Skin skin, Texture defaultAlbumC) {
this.defaultAlbumCover = defaultAlbumC; table = new Table(skin);
this.musicFile = musicFile; table.setBackground("holo-pane");
table.setFillParent(true);
setName(musicFile.name()); setName(musicFile.name());
audioInfo = new AudioInfo(musicFile, musicData); this.albumCover = defaultAlbumC;
this.musicFile = musicFile;
songInfo = new SongInfo(musicFile, musicAnnotation);
defaults().pad(10f); imageIcon = new Image(albumCover);
table.add(imageIcon);
displayName = new ScrollText(musicFile.name(), skin, true);
table.add(displayName);
table.row();
durationLabel = new Label("Loading...", skin, "sub-font");
table.add(durationLabel);
authorLabel = new Label("Loading...", skin, "sub-font");
table.defaults().pad(10f);
} }
public void updateInfo() {
public void addInfoToPanel(float coverSize) { durationLabel.setText("Runtime: "
displayName = new ScrollText(audioInfo.getSongName(), skin, true); + ((songInfo.getDurationInSeconds() / 60 < 1) ? "00" : songInfo.getDurationInSeconds() / 60) + ":"
+ ((songInfo.getDurationInSeconds() - (songInfo.getDurationInSeconds() / 60) * 60) < 10
defaults().align(Align.top); ? "0" + (songInfo.getDurationInSeconds() - (songInfo.getDurationInSeconds() / 60) * 60)
: (songInfo.getDurationInSeconds() - (songInfo.getDurationInSeconds() / 60) * 60)));
add(displayName).expandX().pad(0).fillX().padTop(10f).top().padBottom(10f); authorLabel.setText("Author: " + songInfo.getAuthor());
row();
String formattedTime = "Run time: "+ String.valueOf(audioInfo.getDurationInSeconds()/60) + ":";
if (audioInfo.getDurationInSeconds() - (audioInfo.getDurationInSeconds()/60)*60 < 10) {
formattedTime = formattedTime.concat("0");
}
Table songInfoTable = new Table();
formattedTime = formattedTime.concat(String.valueOf(audioInfo.getDurationInSeconds() - (audioInfo.getDurationInSeconds()/60)*60));
runTime = new Label(formattedTime, skin, "sub-font", skin.getColor("default"));
songInfoTable.add(runTime).expandX().left();
songInfoTable.row();
authorLabel = new Label("Author: " + audioInfo.getAuthor(), skin, "sub-font", skin.getColor("default"));
songInfoTable.add(authorLabel).left();
songInfoTable.row();
previousTopLabel = new Label("High Score: " + (audioInfo.getPreviousTop() != -1 ? audioInfo.getPreviousTop() : "N/A"), skin, "sub-font", skin.getColor("default"));
songInfoTable.add(previousTopLabel).left();
songInfoTable.row();
ratedDifficultyLabel = new Label("Difficulty: " + (audioInfo.getRatedDifficulty() != -1 ? audioInfo.getRatedDifficulty() : "N/A"), skin, "sub-font", skin.getColor("default"));
songInfoTable.add(ratedDifficultyLabel).left();
songInfoTable.row();
row();
add(songInfoTable).expandY().center();
row();
audioInfo.setupTexture(defaultAlbumCover);
imageIcon = new Image(audioInfo.getAlbumCover());
if (audioInfo.isInvalidMusic()) {
imageIcon.setColor(Color.RED);
}
add(imageIcon).expandY().center().pad(15f).size(coverSize);
} }
public FileHandle getMusicFile() { public FileHandle getMusicFile() {
return musicFile; return musicFile;
} }
public AudioInfo getAudioInfo() { public SongInfo getAudioInfo() {
return audioInfo; return songInfo;
} }
@Override @Override
public void dispose() { public void dispose() {
audioInfo.dispose(); songInfo.dispose();
} }
public boolean isMusicInvalid() { public boolean isMusicInvalid() {
return audioInfo.isInvalidMusic(); return songInfo.isInvalidMusic();
} }
public void select() {
table.setBackground("holo-pane-down");
selected = true;
}
public void diselect() {
table.setBackground("holo-pane");
selected = false;
}
public boolean isSelected() {
return selected;
}
} }

View File

@ -24,7 +24,7 @@ public class ScrollText extends Widget {
private float fontWidth; private float fontWidth;
private boolean scrollOnHover; private boolean scrollOnHover;
private boolean currentlyHovering; private boolean scroll;
private float textOffset; private float textOffset;
@ -47,13 +47,13 @@ public class ScrollText extends Widget {
addListener(new ClickListener() { addListener(new ClickListener() {
@Override @Override
public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) { public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) {
currentlyHovering = true; scroll = true;
super.enter(event, x, y, pointer, fromActor); super.enter(event, x, y, pointer, fromActor);
} }
@Override @Override
public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) { public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) {
currentlyHovering = false; scroll = false;
super.exit(event, x, y, pointer, toActor); super.exit(event, x, y, pointer, toActor);
} }
@ -81,13 +81,13 @@ public class ScrollText extends Widget {
addListener(new ClickListener() { addListener(new ClickListener() {
@Override @Override
public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) { public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) {
currentlyHovering = true; scroll = true;
super.enter(event, x, y, pointer, fromActor); super.enter(event, x, y, pointer, fromActor);
} }
@Override @Override
public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) { public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) {
currentlyHovering = false; scroll = false;
super.exit(event, x, y, pointer, toActor); super.exit(event, x, y, pointer, toActor);
} }
@ -116,7 +116,7 @@ public class ScrollText extends Widget {
public void act(float delta) { public void act(float delta) {
if (fontWidth > clipBounds.getWidth()) { if (fontWidth > clipBounds.getWidth()) {
if (scrollOnHover) { if (scrollOnHover) {
if ((int) textOffset != 0 || currentlyHovering) { if ((int) textOffset != 0 || scroll) {
if (textOffset < -fontWidth) { if (textOffset < -fontWidth) {
textOffset = clipBounds.getWidth(); textOffset = clipBounds.getWidth();
} }

View File

@ -1,33 +0,0 @@
package zero1hd.rhythmbullet.ui.builders;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.scenes.scene2d.Actor;
import edu.emory.mathcs.jtransforms.fft.FloatFFT_1D;
import zero1hd.rhythmbullet.audio.CoreMusicInfo;
public class Visualizer extends Actor {
private CoreMusicInfo cmi;
private FloatFFT_1D fft;
float[] audioPCM;
public Visualizer() {
fft = new FloatFFT_1D(cmi.getReadWindowSize());
audioPCM = new float[cmi.getReadWindowSize()];
setSize(Gdx.graphics.getHeight()*0.6f, Gdx.graphics.getHeight()*0.6f);
}
@Override
public void act(float delta) {
if (cmi.getPlaybackIndexPosition() > cmi.getCurrentReadWindowIndex()) {
cmi.readSamples(audioPCM);
Gdx.app.debug("Visualizer", "Skipping a frame to catch up to music.");
} else {
Gdx.app.debug("Visualizer", "Not reading so music can catch up.");
}
fft.realForward(audioPCM);
super.act(delta);
}
}

View File

@ -20,7 +20,7 @@ import com.badlogic.gdx.utils.Disposable;
import zero1hd.rhythmbullet.RhythmBullet; import zero1hd.rhythmbullet.RhythmBullet;
import zero1hd.rhythmbullet.audio.AudioAnalyzer; import zero1hd.rhythmbullet.audio.AudioAnalyzer;
import zero1hd.rhythmbullet.audio.CoreMusicInfo; import zero1hd.rhythmbullet.audio.CoreMusicInfo;
import zero1hd.rhythmbullet.audio.AudioInfo; import zero1hd.rhythmbullet.audio.SongInfo;
import zero1hd.rhythmbullet.audio.map.GamePlayMap; import zero1hd.rhythmbullet.audio.map.GamePlayMap;
import zero1hd.rhythmbullet.audio.map.RhythmMapAlgorithm; import zero1hd.rhythmbullet.audio.map.RhythmMapAlgorithm;
import zero1hd.rhythmbullet.screens.GameScreen; import zero1hd.rhythmbullet.screens.GameScreen;
@ -186,7 +186,7 @@ public class AnalyzePage extends Page implements MiniListener, Disposable {
addActor(back); addActor(back);
} }
public void setSong(CoreMusicInfo music, AudioInfo audioInfo, MiniListener listener) { public void setSong(CoreMusicInfo music, SongInfo audioInfo, MiniListener listener) {
confirmed = false; confirmed = false;
confirmDiffButton.setDisabled(false); confirmDiffButton.setDisabled(false);
sensitivityRating.setDisabled(false); sensitivityRating.setDisabled(false);

View File

@ -1,7 +1,10 @@
package zero1hd.rhythmbullet.ui.pages; package zero1hd.rhythmbullet.ui.pages;
import java.util.Random;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.InputEvent;
@ -14,6 +17,9 @@ import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import zero1hd.rhythmbullet.RhythmBullet; import zero1hd.rhythmbullet.RhythmBullet;
import zero1hd.rhythmbullet.audio.CoreMusicInfo;
import zero1hd.rhythmbullet.audio.SongList;
import zero1hd.rhythmbullet.audio.visualizer.HorizontalVisualizer;
import zero1hd.rhythmbullet.screens.PreGameScreen; import zero1hd.rhythmbullet.screens.PreGameScreen;
public class MainPage extends Page { public class MainPage extends Page {
@ -26,7 +32,18 @@ public class MainPage extends Page {
private TextButton credits; private TextButton credits;
private WidgetGroup playButton; private WidgetGroup playButton;
public MainPage(final RhythmBullet core, final Vector3 targetPosition) { private HorizontalVisualizer hvisual;
private CoreMusicInfo cmi;
private SongList songList;
private Random rand;
public MainPage(RhythmBullet core, Vector3 targetPosition, SongList sl) {
hvisual = new HorizontalVisualizer();
this.songList = sl;
rand = new Random();
cmi = songList.getMusicInfoFromIndex(rand.nextInt(songList.getAmountOfSongs()));
hvisual.setCmi(cmi);
title = new Image(core.getAssetManager().get("title.png", Texture.class)); title = new Image(core.getAssetManager().get("title.png", Texture.class));
title.setPosition(10, getHeight() - title.getHeight()-30); title.setPosition(10, getHeight() - title.getHeight()-30);
addActor(title); addActor(title);
@ -98,7 +115,7 @@ public class MainPage extends Page {
Actions.run(new Runnable() { Actions.run(new Runnable() {
@Override @Override
public void run() { public void run() {
core.setScreen(new PreGameScreen(core)); core.setScreen(new PreGameScreen(core, songList));
} }
}), Actions.parallel(Actions.scaleTo(1, 1), Actions.alpha(0.6f)))); }), Actions.parallel(Actions.scaleTo(1, 1), Actions.alpha(0.6f))));
} }
@ -109,4 +126,10 @@ public class MainPage extends Page {
// end play button // end play button
} }
@Override
public void draw(Batch batch, float parentAlpha) {
hvisual.update();
hvisual.render(batch, parentAlpha);
super.draw(batch, parentAlpha);
}
} }

View File

@ -1,159 +1,95 @@
package zero1hd.rhythmbullet.ui.pages; package zero1hd.rhythmbullet.ui.pages;
import java.io.File; import java.util.concurrent.ExecutorService;
import java.io.FilenameFilter; import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Preferences; import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.Array;
import zero1hd.rhythmbullet.RhythmBullet; import zero1hd.rhythmbullet.audio.SongInfo;
import zero1hd.rhythmbullet.audio.AudioInfo; import zero1hd.rhythmbullet.audio.SongList;
import zero1hd.rhythmbullet.ui.builders.MusicSelectable; import zero1hd.rhythmbullet.ui.builders.MusicSelectable;
import zero1hd.rhythmbullet.ui.windows.LoadingWindow;
import zero1hd.rhythmbullet.ui.windows.NoticeWindow;
import zero1hd.rhythmbullet.util.MiniEvents; import zero1hd.rhythmbullet.util.MiniEvents;
public class MusicSelectionPage extends Page { public class MusicSelectionPage extends Page {
private volatile Table musicChoices;
Preferences musicFileAnnotation; Preferences musicFileAnnotation;
private RhythmBullet core;
private volatile ScrollPane musicChoiceScroller;
private volatile LoadingWindow loadingWindow; private SongList songList;
protected volatile boolean cancel; private Array<MusicSelectable> selectables;
private Table songTable;
private ScrollPane scrollbar;
private TextButton back; private TextButton back;
private FileHandle selectedMusic; private FileHandle selectedMusic;
private AudioInfo selectedMusicInfo; private SongInfo selectedMusicInfo;
public MusicSelectionPage(final RhythmBullet core) {
super("Select music", core.getDefaultSkin());
this.core = core;
private Skin skin;
private AssetManager assets;
public MusicSelectionPage(Skin skin, SongList songList, AssetManager assetManager) {
super("Select music", skin);
this.songList = songList;
musicFileAnnotation = Gdx.app.getPreferences("music_file_annotation"); musicFileAnnotation = Gdx.app.getPreferences("music_file_annotation");
this.assets = assetManager;
back = new TextButton("Back", core.getDefaultSkin()); songTable = new Table(skin);
scrollbar = new ScrollPane(songTable, skin);
scrollbar.setSize(0.4f*getWidth(), getHeightBelowTitle());
addActor(scrollbar);
selectables = new Array<>();
this.skin = skin;
back = new TextButton("Back", skin);
back.setPosition(getWidth()-back.getWidth()-15f, getHeightBelowTitle()); back.setPosition(getWidth()-back.getWidth()-15f, getHeightBelowTitle());
back.addListener(new ChangeListener() { back.addListener(new ChangeListener() {
@Override @Override
public void changed(ChangeEvent event, Actor actor) { public void changed(ChangeEvent event, Actor actor) {
miniSender.send(MiniEvents.BACK); miniSender.send(MiniEvents.BACK);
cancel = true;
} }
}); });
addActor(back); addActor(back);
loadingWindow = new LoadingWindow(core.getDefaultSkin(), "tinted", true, core.getAssetManager(), core.getPrefs().getFloat("fx vol"));
loadingWindow.setPosition((getWidth()-loadingWindow.getWidth())/2f, (getHeight()-loadingWindow.getHeight())/2f);
addActor(loadingWindow);
loadingWindow.playOpenSound();
loadingWindow.setMovable(false);
loadingWindow.setModal(true);
musicChoices = new Table();
musicChoices.defaults().pad(10f);
musicChoiceScroller = new ScrollPane(musicChoices);
musicChoiceScroller.setScrollingDisabled(false, true);
musicChoiceScroller.setSize(getWidth(), getHeight()-(getHeight()-back.getY()));
addActor(musicChoiceScroller);
loadingWindow.toFront();
back.toFront(); back.toFront();
} }
@Override @Override
public void act(float delta) { public void act(float delta) {
back.toFront();
super.act(delta); super.act(delta);
} }
public void beginMusicSearch() {
new Thread(new Runnable() {
@Override
public void run() {
Logger.getLogger("org.jaudiotagger").setLevel(Level.SEVERE);
FileHandle[] musicFiles = new FileHandle(core.getPrefs().getString("music dir")).list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
if (name.endsWith("mp3") || name.endsWith("wav")) {
return true;
}
return false;
}
});
if (musicFiles.length > 0) {
for (int music = 0; music < musicFiles.length && !cancel; music++) {
final MusicSelectable selectable = new MusicSelectable(musicFiles[music], musicFileAnnotation, core.getDefaultSkin(), core.getAssetManager().get("defaultCover.png", Texture.class));
Gdx.app.postRunnable(new Runnable() {
@Override
public void run() {
Gdx.app.debug("Music Search Thread", "Finished loading: " + selectable.getName());
musicChoices.add(selectable).prefSize(panelWidthCalc(getWidth()), musicChoiceScroller.getHeight());
selectable.addInfoToPanel(panelWidthCalc(getWidth()) - 20f);
selectable.addListener(new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
if (!selectable.isMusicInvalid()) {
selectedMusic = selectable.getMusicFile();
selectedMusicInfo = selectable.getAudioInfo();
miniSender.send(MiniEvents.MUSIC_SELECTED);
} else {
//Play "no" sound
}
}
});
}
});
Gdx.app.debug("Music Search Thread", "Completed: " + music);
int prog = (int) (100f*music/(musicFiles.length-1f));
loadingWindow.setProgress(prog);
}
} else {
NoticeWindow notice = new NoticeWindow(core.getDefaultSkin(), "default", "No song's found in:\n\"" + core.getPrefs().getString("music dir") + "\"\nTo change the search directory, go to game options.", core.getPrefs().getFloat("fx vol"), core.getAssetManager());
notice.setSize(0.6f*getWidth(), 0.6f*getHeight());
notice.setPosition((getWidth()-notice.getWidth())/2f, (getHeight()-notice.getHeight())/2f);
notice.setModal(true);
notice.setMovable(false);
addActor(notice);
notice.playOpenSound();
}
loadingWindow.remove();
}
}).start();
}
public float panelWidthCalc(float origWidth) {
return (float) (Math.sqrt(getWidth()*35f)+80f);
}
public FileHandle getSelectedMusic() { public FileHandle getSelectedMusic() {
return selectedMusic; return selectedMusic;
} }
public AudioInfo getSelectedMusicInfo() { public SongInfo getSelectedMusicInfo() {
return selectedMusicInfo; return selectedMusicInfo;
} }
@Override public void refresh() {
public synchronized void addActor(Actor actor) { for (int i = 0; i < songList.getAmountOfSongs(); i++) {
super.addActor(actor); MusicSelectable selectable = new MusicSelectable(songList.getSongList().get(i), musicFileAnnotation, skin, assets.get("defaultCover.png", Texture.class));
selectables.add(selectable);
songTable.add(selectable);
songTable.row();
}
ExecutorService exec = Executors.newSingleThreadExecutor();
exec.submit(() -> {
for (int i = 0; i < selectables.size; i++) {
MusicSelectable info = selectables.get(i);
info.getAudioInfo().loadInfo();
info.getAudioInfo().doesContainsInformation();
Gdx.app.postRunnable(() -> {
info.updateInfo();
});
}
});
} }
} }

View File

@ -17,6 +17,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextField;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import zero1hd.rhythmbullet.RhythmBullet; import zero1hd.rhythmbullet.RhythmBullet;
import zero1hd.rhythmbullet.audio.SongList;
import zero1hd.rhythmbullet.screens.CreativeScreen; import zero1hd.rhythmbullet.screens.CreativeScreen;
import zero1hd.rhythmbullet.screens.MainMenu; import zero1hd.rhythmbullet.screens.MainMenu;
@ -26,7 +27,7 @@ public class OptionsPage extends Page {
private ProgressBar fxVolSlider; private ProgressBar fxVolSlider;
private TextField directoryField; private TextField directoryField;
public OptionsPage(final RhythmBullet core, final Vector3 targetPosition, final MoreOptionsPage moreOptionsPage) { public OptionsPage(final RhythmBullet core, final Vector3 targetPosition, final MoreOptionsPage moreOptionsPage, SongList sl) {
optionsTable.defaults().spaceLeft(40f).padTop(5f).padBottom(5f).left(); optionsTable.defaults().spaceLeft(40f).padTop(5f).padBottom(5f).left();
Label optionGeneralTitle = new Label("General", core.getDefaultSkin(), "large-font", core.getDefaultSkin().getColor("default")); Label optionGeneralTitle = new Label("General", core.getDefaultSkin(), "large-font", core.getDefaultSkin().getColor("default"));
@ -128,7 +129,7 @@ public class OptionsPage extends Page {
Gdx.app.debug("Debug Field", debugCodeField.getText()); Gdx.app.debug("Debug Field", debugCodeField.getText());
if (debugCodeField.getText().equals("creative")) { if (debugCodeField.getText().equals("creative")) {
Gdx.app.debug("Debug Field", "going to creative test room..."); Gdx.app.debug("Debug Field", "going to creative test room...");
core.setScreen(new CreativeScreen(core, (MainMenu) core.getScreen())); core.setScreen(new CreativeScreen(core, (MainMenu) core.getScreen(), sl));
} }
} }
return super.keyUp(event, keycode); return super.keyUp(event, keycode);

View File

@ -11,8 +11,8 @@ import com.badlogic.gdx.scenes.scene2d.ui.Window;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import zero1hd.rhythmbullet.audio.Audio;
import zero1hd.rhythmbullet.audio.CoreMusicInfo; import zero1hd.rhythmbullet.audio.CoreMusicInfo;
import zero1hd.rhythmbullet.audio.SongList;
import zero1hd.rhythmbullet.util.MiniEvents; import zero1hd.rhythmbullet.util.MiniEvents;
import zero1hd.rhythmbullet.util.MiniSender; import zero1hd.rhythmbullet.util.MiniSender;
@ -22,23 +22,23 @@ public class MusicSelector extends Window {
FileHandle selectedMusic; FileHandle selectedMusic;
Array<String> fileNames; Array<String> fileNames;
private List<String> musicList; private List<String> musicList;
private String path;
private ScrollPane listScroller; private ScrollPane listScroller;
private SongList songList;
public MiniSender miniSender; public MiniSender miniSender;
public MusicSelector(String title, Skin skin, final String path, String listStyle) { public MusicSelector(String title, Skin skin, final String path, SongList songList) {
super(title, skin, "tinted"); super(title, skin, "tinted");
this.path = path;
padTop(25f); padTop(25f);
padLeft(5f); padLeft(5f);
padRight(5f); padRight(5f);
this.songList = songList;
miniSender = new MiniSender(); miniSender = new MiniSender();
setSize(Gdx.graphics.getWidth()*0.5f, Gdx.graphics.getHeight()*0.5f); setSize(Gdx.graphics.getWidth()*0.5f, Gdx.graphics.getHeight()*0.5f);
fileNames = new Array<>(); fileNames = new Array<>();
musicList = new List<String>(skin, listStyle); musicList = new List<String>(skin, "default");
TextButton confirmButton = new TextButton("confirm", skin, "window"); TextButton confirmButton = new TextButton("confirm", skin, "window");
confirmButton.addListener(new ChangeListener() { confirmButton.addListener(new ChangeListener() {
@ -71,15 +71,8 @@ public class MusicSelector extends Window {
} }
public void refresh() { public void refresh() {
fileNames.clear(); songList.refresh();
FileHandle[] musicListArray = Gdx.files.absolute(path).list(); musicList.setItems(songList.getSongList());
for (int i = 0; i < musicListArray.length; i++) {
if (musicListArray[i].name().toLowerCase().endsWith(".wav") || musicListArray[i].name().toLowerCase().endsWith(".mp3")) {
fileNames.add(musicListArray[i].name());
}
}
fileNames.sort();
musicList.setItems(fileNames);
} }
@ -97,7 +90,7 @@ public class MusicSelector extends Window {
public CoreMusicInfo getSelectedMusic() { public CoreMusicInfo getSelectedMusic() {
if (selectedMusic != null) { if (selectedMusic != null) {
return Audio.getAudioData(selectedMusic); return songList.getAudioData(selectedMusic);
} else { } else {
return null; return null;
} }