diff --git a/android/assets/uiskin.png b/android/assets/uiskin.png index 960d314..1c5bd49 100755 Binary files a/android/assets/uiskin.png and b/android/assets/uiskin.png differ diff --git a/core/src/zero1hd/rhythmbullet/RhythmBullet.java b/core/src/zero1hd/rhythmbullet/RhythmBullet.java index 76070fb..0b240ed 100755 --- a/core/src/zero1hd/rhythmbullet/RhythmBullet.java +++ b/core/src/zero1hd/rhythmbullet/RhythmBullet.java @@ -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.FreeTypeFontParameter; 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.Label.LabelStyle; import com.badlogic.gdx.scenes.scene2d.ui.List.ListStyle; @@ -53,7 +52,6 @@ public class RhythmBullet extends Game { private Preferences prefs; private RoundingResolutionHandler rRHandler; - @Override public void create() { Gdx.app.setLogLevel(Application.LOG_DEBUG); @@ -113,7 +111,7 @@ public class RhythmBullet extends Game { public void dispose() { Gdx.app.debug("Core", "disposing..."); if (initComplete) { -// skinAtlas.dispose(); + skinAtlas.dispose(); getDefaultSkin().dispose(); default_fontGenerator.dispose(); darktech_ldr_fontGenerator.dispose(); @@ -252,11 +250,6 @@ public class RhythmBullet extends Game { vertSlider.knob = getDefaultSkin().getDrawable("vertical-slider-knob"); 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(); defaultLabel.font = getDefaultSkin().getFont("default-font"); defaultLabel.fontColor = getDefaultSkin().getColor("default"); diff --git a/core/src/zero1hd/rhythmbullet/audio/Audio.java b/core/src/zero1hd/rhythmbullet/audio/Audio.java deleted file mode 100755 index ddfde16..0000000 --- a/core/src/zero1hd/rhythmbullet/audio/Audio.java +++ /dev/null @@ -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; - } -} diff --git a/core/src/zero1hd/rhythmbullet/audio/AudioInfo.java b/core/src/zero1hd/rhythmbullet/audio/SongInfo.java similarity index 78% rename from core/src/zero1hd/rhythmbullet/audio/AudioInfo.java rename to core/src/zero1hd/rhythmbullet/audio/SongInfo.java index 4ca9ee9..b5ecb7c 100755 --- a/core/src/zero1hd/rhythmbullet/audio/AudioInfo.java +++ b/core/src/zero1hd/rhythmbullet/audio/SongInfo.java @@ -18,7 +18,7 @@ import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.utils.Disposable; -public class AudioInfo implements Disposable { +public class SongInfo implements Disposable { private long durationInSeconds; private String songName; private Texture albumCover; @@ -28,7 +28,17 @@ public class AudioInfo implements Disposable { private byte[] albumWorkBytes; 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")) { MP3File mp3File; try { @@ -68,8 +78,8 @@ public class AudioInfo implements Disposable { songName = musicFile.nameWithoutExtension(); } - previousTop = musicData.getInteger(songName + ":previous top", -1); - ratedDifficulty = musicData.getInteger(songName + ":difficulty", -1); + previousTop = musicAnnotation.getInteger(songName + ":previous top", -1); + ratedDifficulty = musicAnnotation.getInteger(songName + ":difficulty", -1); if (author == null || author.isEmpty()) { author = "N/A"; @@ -119,4 +129,18 @@ public class AudioInfo implements Disposable { 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; + } } diff --git a/core/src/zero1hd/rhythmbullet/audio/SongList.java b/core/src/zero1hd/rhythmbullet/audio/SongList.java new file mode 100755 index 0000000..2a0aa74 --- /dev/null +++ b/core/src/zero1hd/rhythmbullet/audio/SongList.java @@ -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 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 getSongList() { + return songList; + } + + public int getAmountOfSongs() { + return songList.size; + } +} diff --git a/core/src/zero1hd/rhythmbullet/audio/WavAudioData.java b/core/src/zero1hd/rhythmbullet/audio/WavAudioData.java index b71ec12..e7bb089 100755 --- a/core/src/zero1hd/rhythmbullet/audio/WavAudioData.java +++ b/core/src/zero1hd/rhythmbullet/audio/WavAudioData.java @@ -9,7 +9,7 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.audio.Music; import com.badlogic.gdx.files.FileHandle; -import zero1hd.wavedecoder.WavDecoder; +import zero1hd.rhythmbullet.audio.wavedecoder.WavDecoder; public class WavAudioData implements CoreMusicInfo { private int readWindowSize = 1024; diff --git a/core/src/zero1hd/rhythmbullet/audio/visualizer/HorizontalVisualizer.java b/core/src/zero1hd/rhythmbullet/audio/visualizer/HorizontalVisualizer.java new file mode 100755 index 0000000..4a6b753 --- /dev/null +++ b/core/src/zero1hd/rhythmbullet/audio/visualizer/HorizontalVisualizer.java @@ -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(); + } +} diff --git a/core/src/zero1hd/rhythmbullet/audio/visualizer/VisualizerCore.java b/core/src/zero1hd/rhythmbullet/audio/visualizer/VisualizerCore.java new file mode 100755 index 0000000..dc54dd2 --- /dev/null +++ b/core/src/zero1hd/rhythmbullet/audio/visualizer/VisualizerCore.java @@ -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 + + } + +} diff --git a/core/src/zero1hd/wavedecoder/WavDecoder.java b/core/src/zero1hd/rhythmbullet/audio/wavedecoder/WavDecoder.java similarity index 97% rename from core/src/zero1hd/wavedecoder/WavDecoder.java rename to core/src/zero1hd/rhythmbullet/audio/wavedecoder/WavDecoder.java index 29e39fa..b545457 100755 --- a/core/src/zero1hd/wavedecoder/WavDecoder.java +++ b/core/src/zero1hd/rhythmbullet/audio/wavedecoder/WavDecoder.java @@ -1,4 +1,4 @@ -package zero1hd.wavedecoder; +package zero1hd.rhythmbullet.audio.wavedecoder; import java.io.IOException; diff --git a/core/src/zero1hd/rhythmbullet/screens/CreativeScreen.java b/core/src/zero1hd/rhythmbullet/screens/CreativeScreen.java index eb9ae2a..c5f2da2 100755 --- a/core/src/zero1hd/rhythmbullet/screens/CreativeScreen.java +++ b/core/src/zero1hd/rhythmbullet/screens/CreativeScreen.java @@ -3,6 +3,7 @@ package zero1hd.rhythmbullet.screens; import com.badlogic.gdx.Preferences; import zero1hd.rhythmbullet.RhythmBullet; +import zero1hd.rhythmbullet.audio.SongList; import zero1hd.rhythmbullet.stages.CreativeHUD; public class CreativeScreen extends GameScreen { @@ -10,9 +11,9 @@ public class CreativeScreen extends GameScreen { Preferences prefs; - public CreativeScreen(RhythmBullet core, MainMenu mainMenu) { + public CreativeScreen(RhythmBullet core, MainMenu mainMenu, SongList sl) { super(core, mainMenu); - chud = new CreativeHUD(core, mainMenu, gameArea, gameHUD); + chud = new CreativeHUD(core, mainMenu, gameArea, gameHUD, sl); inputs.addProcessor(chud); this.prefs = core.getPrefs(); diff --git a/core/src/zero1hd/rhythmbullet/screens/MainMenu.java b/core/src/zero1hd/rhythmbullet/screens/MainMenu.java index 52d46ab..730b5bb 100755 --- a/core/src/zero1hd/rhythmbullet/screens/MainMenu.java +++ b/core/src/zero1hd/rhythmbullet/screens/MainMenu.java @@ -12,6 +12,7 @@ import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.utils.viewport.ScreenViewport; import zero1hd.rhythmbullet.RhythmBullet; +import zero1hd.rhythmbullet.audio.SongList; import zero1hd.rhythmbullet.ui.pages.CreditsPage; import zero1hd.rhythmbullet.ui.pages.MainPage; import zero1hd.rhythmbullet.ui.pages.MoreOptionsPage; @@ -29,12 +30,16 @@ public class MainMenu extends ScreenAdapter implements TransitionAdapter { private RhythmBullet core; + private SongList songList; private float lerpAlpha; public MainMenu(final RhythmBullet core) { this.core = core; stage = new Stage(new ScreenViewport()); targetPosition = new Vector3(stage.getCamera().position); - + + songList = new SongList(); + songList.setSearchPath(core.getPrefs().getString("music dir")); + songList.refresh(); postTransition(); } @@ -49,14 +54,14 @@ public class MainMenu extends ScreenAdapter implements TransitionAdapter { @Override public void postTransition() { - mainPage = new MainPage(core, targetPosition); + mainPage = new MainPage(core, targetPosition, songList); mainPage.setPosition(0, 0); stage.addActor(mainPage); //End main menu moreOptionsPage = new MoreOptionsPage(core, targetPosition); - optionsPage = new OptionsPage(core, targetPosition, moreOptionsPage); + optionsPage = new OptionsPage(core, targetPosition, moreOptionsPage, songList); optionsPage.setPosition(Gdx.graphics.getWidth(), 0); stage.addActor(optionsPage); @@ -119,13 +124,11 @@ public class MainMenu extends ScreenAdapter implements TransitionAdapter { @Override 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); stage.act(); - stage.draw(); if (stage.getCamera().position.x != targetPosition.x || stage.getCamera().position.y != targetPosition.y) { - stage.getCamera().position.lerp(targetPosition, lerpAlpha); } diff --git a/core/src/zero1hd/rhythmbullet/screens/PreGameScreen.java b/core/src/zero1hd/rhythmbullet/screens/PreGameScreen.java index 543037b..29a0b6a 100755 --- a/core/src/zero1hd/rhythmbullet/screens/PreGameScreen.java +++ b/core/src/zero1hd/rhythmbullet/screens/PreGameScreen.java @@ -8,14 +8,14 @@ import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.utils.viewport.ScreenViewport; 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.MusicSelectionPage; import zero1hd.rhythmbullet.util.MiniEvents; import zero1hd.rhythmbullet.util.MiniListener; import zero1hd.rhythmbullet.util.TransitionAdapter; - +@Deprecated public class PreGameScreen extends ScreenAdapter implements TransitionAdapter, MiniListener { Stage stage; @@ -23,11 +23,13 @@ public class PreGameScreen extends ScreenAdapter implements TransitionAdapter, M public AnalyzePage ap; private Vector3 cameraPos; private RhythmBullet core; + private SongList songList; - public PreGameScreen(RhythmBullet core) { + public PreGameScreen(RhythmBullet core, SongList songList) { stage = new Stage(new ScreenViewport()); cameraPos = new Vector3(stage.getCamera().position); this.core = core; + this.songList = songList; postTransition(); } @@ -62,7 +64,7 @@ public class PreGameScreen extends ScreenAdapter implements TransitionAdapter, M switch (ID) { case MUSIC_SELECTED: 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; case BACK: if (cameraPos.x == 1.5f*Gdx.graphics.getWidth()) { @@ -85,9 +87,8 @@ public class PreGameScreen extends ScreenAdapter implements TransitionAdapter, M @Override public void postTransition() { - ms = new MusicSelectionPage(core); + ms = new MusicSelectionPage(core.getDefaultSkin(), songList, core.getAssetManager()); ms.miniSender.addListener(this); - ms.beginMusicSearch(); stage.addActor(ms); ap = new AnalyzePage(core); diff --git a/core/src/zero1hd/rhythmbullet/stages/CreativeHUD.java b/core/src/zero1hd/rhythmbullet/stages/CreativeHUD.java index 6d024db..a32eba4 100755 --- a/core/src/zero1hd/rhythmbullet/stages/CreativeHUD.java +++ b/core/src/zero1hd/rhythmbullet/stages/CreativeHUD.java @@ -16,6 +16,7 @@ import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import zero1hd.rhythmbullet.RhythmBullet; import zero1hd.rhythmbullet.audio.AudioAnalyzer; import zero1hd.rhythmbullet.audio.AudioDataPackage; +import zero1hd.rhythmbullet.audio.SongList; import zero1hd.rhythmbullet.audio.map.RhythmMapAlgorithm; import zero1hd.rhythmbullet.screens.MainMenu; import zero1hd.rhythmbullet.ui.builders.AudioGraph; @@ -46,11 +47,11 @@ public class CreativeHUD extends Stage implements MiniListener { GamePlayArea gpa; 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.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.refresh(); diff --git a/core/src/zero1hd/rhythmbullet/ui/builders/MusicSelectable.java b/core/src/zero1hd/rhythmbullet/ui/builders/MusicSelectable.java index 07bcb49..e2b1ce4 100755 --- a/core/src/zero1hd/rhythmbullet/ui/builders/MusicSelectable.java +++ b/core/src/zero1hd/rhythmbullet/ui/builders/MusicSelectable.java @@ -2,107 +2,95 @@ package zero1hd.rhythmbullet.ui.builders; import com.badlogic.gdx.Preferences; import com.badlogic.gdx.files.FileHandle; -import com.badlogic.gdx.graphics.Color; 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.Label; import com.badlogic.gdx.scenes.scene2d.ui.Skin; 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 zero1hd.rhythmbullet.audio.AudioInfo; +import zero1hd.rhythmbullet.audio.SongInfo; + +public class MusicSelectable extends Widget implements Disposable { + private Table table; -public class MusicSelectable extends Button implements Disposable { - private Image imageIcon; private ScrollText displayName; - private Label runTime; + private Label durationLabel; private Label authorLabel; - private Label previousTopLabel; - private Label ratedDifficultyLabel; - private Skin skin; - - private FileHandle musicFile; - - private Texture defaultAlbumCover; - AudioInfo audioInfo; - - public MusicSelectable(FileHandle musicFile, Preferences musicData, final Skin skin, Texture defaultAlbumC) { - super(skin, "info-button"); - this.skin = skin; - this.defaultAlbumCover = defaultAlbumC; - this.musicFile = musicFile; - - setName(musicFile.name()); - - audioInfo = new AudioInfo(musicFile, musicData); - - defaults().pad(10f); - } - - - public void addInfoToPanel(float coverSize) { - displayName = new ScrollText(audioInfo.getSongName(), skin, true); - - defaults().align(Align.top); - - add(displayName).expandX().pad(0).fillX().padTop(10f).top().padBottom(10f); - 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); - } + private FileHandle musicFile; + + private Texture albumCover; + private SongInfo songInfo; + private boolean selected; + + public MusicSelectable(FileHandle musicFile, Preferences musicAnnotation, Skin skin, Texture defaultAlbumC) { + table = new Table(skin); + table.setBackground("holo-pane"); + table.setFillParent(true); + + setName(musicFile.name()); + + this.albumCover = defaultAlbumC; + this.musicFile = musicFile; + songInfo = new SongInfo(musicFile, musicAnnotation); + + 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() { + durationLabel.setText("Runtime: " + + ((songInfo.getDurationInSeconds() / 60 < 1) ? "00" : songInfo.getDurationInSeconds() / 60) + ":" + + ((songInfo.getDurationInSeconds() - (songInfo.getDurationInSeconds() / 60) * 60) < 10 + ? "0" + (songInfo.getDurationInSeconds() - (songInfo.getDurationInSeconds() / 60) * 60) + : (songInfo.getDurationInSeconds() - (songInfo.getDurationInSeconds() / 60) * 60))); + authorLabel.setText("Author: " + songInfo.getAuthor()); + } + public FileHandle getMusicFile() { return musicFile; } - - public AudioInfo getAudioInfo() { - return audioInfo; + + public SongInfo getAudioInfo() { + return songInfo; } - + @Override public void dispose() { - audioInfo.dispose(); + songInfo.dispose(); } - + 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; + } } diff --git a/core/src/zero1hd/rhythmbullet/ui/builders/ScrollText.java b/core/src/zero1hd/rhythmbullet/ui/builders/ScrollText.java index 94fa3ea..9962575 100755 --- a/core/src/zero1hd/rhythmbullet/ui/builders/ScrollText.java +++ b/core/src/zero1hd/rhythmbullet/ui/builders/ScrollText.java @@ -24,7 +24,7 @@ public class ScrollText extends Widget { private float fontWidth; private boolean scrollOnHover; - private boolean currentlyHovering; + private boolean scroll; private float textOffset; @@ -47,13 +47,13 @@ public class ScrollText extends Widget { addListener(new ClickListener() { @Override public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) { - currentlyHovering = true; + scroll = true; super.enter(event, x, y, pointer, fromActor); } @Override public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) { - currentlyHovering = false; + scroll = false; super.exit(event, x, y, pointer, toActor); } @@ -81,13 +81,13 @@ public class ScrollText extends Widget { addListener(new ClickListener() { @Override public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) { - currentlyHovering = true; + scroll = true; super.enter(event, x, y, pointer, fromActor); } @Override public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) { - currentlyHovering = false; + scroll = false; super.exit(event, x, y, pointer, toActor); } @@ -116,7 +116,7 @@ public class ScrollText extends Widget { public void act(float delta) { if (fontWidth > clipBounds.getWidth()) { if (scrollOnHover) { - if ((int) textOffset != 0 || currentlyHovering) { + if ((int) textOffset != 0 || scroll) { if (textOffset < -fontWidth) { textOffset = clipBounds.getWidth(); } diff --git a/core/src/zero1hd/rhythmbullet/ui/builders/Visualizer.java b/core/src/zero1hd/rhythmbullet/ui/builders/Visualizer.java deleted file mode 100755 index f04bd49..0000000 --- a/core/src/zero1hd/rhythmbullet/ui/builders/Visualizer.java +++ /dev/null @@ -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); - } -} diff --git a/core/src/zero1hd/rhythmbullet/ui/pages/AnalyzePage.java b/core/src/zero1hd/rhythmbullet/ui/pages/AnalyzePage.java index d0f463e..09830c6 100755 --- a/core/src/zero1hd/rhythmbullet/ui/pages/AnalyzePage.java +++ b/core/src/zero1hd/rhythmbullet/ui/pages/AnalyzePage.java @@ -20,7 +20,7 @@ import com.badlogic.gdx.utils.Disposable; import zero1hd.rhythmbullet.RhythmBullet; import zero1hd.rhythmbullet.audio.AudioAnalyzer; 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.RhythmMapAlgorithm; import zero1hd.rhythmbullet.screens.GameScreen; @@ -186,7 +186,7 @@ public class AnalyzePage extends Page implements MiniListener, Disposable { addActor(back); } - public void setSong(CoreMusicInfo music, AudioInfo audioInfo, MiniListener listener) { + public void setSong(CoreMusicInfo music, SongInfo audioInfo, MiniListener listener) { confirmed = false; confirmDiffButton.setDisabled(false); sensitivityRating.setDisabled(false); diff --git a/core/src/zero1hd/rhythmbullet/ui/pages/MainPage.java b/core/src/zero1hd/rhythmbullet/ui/pages/MainPage.java index 0b0b725..3d1a501 100755 --- a/core/src/zero1hd/rhythmbullet/ui/pages/MainPage.java +++ b/core/src/zero1hd/rhythmbullet/ui/pages/MainPage.java @@ -1,7 +1,10 @@ package zero1hd.rhythmbullet.ui.pages; +import java.util.Random; + import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.scenes.scene2d.Actor; 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 zero1hd.rhythmbullet.RhythmBullet; +import zero1hd.rhythmbullet.audio.CoreMusicInfo; +import zero1hd.rhythmbullet.audio.SongList; +import zero1hd.rhythmbullet.audio.visualizer.HorizontalVisualizer; import zero1hd.rhythmbullet.screens.PreGameScreen; public class MainPage extends Page { @@ -25,8 +31,19 @@ public class MainPage extends Page { private TextButton quit; private TextButton credits; 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.setPosition(10, getHeight() - title.getHeight()-30); addActor(title); @@ -98,7 +115,7 @@ public class MainPage extends Page { Actions.run(new Runnable() { @Override public void run() { - core.setScreen(new PreGameScreen(core)); + core.setScreen(new PreGameScreen(core, songList)); } }), Actions.parallel(Actions.scaleTo(1, 1), Actions.alpha(0.6f)))); } @@ -109,4 +126,10 @@ public class MainPage extends Page { // end play button } + @Override + public void draw(Batch batch, float parentAlpha) { + hvisual.update(); + hvisual.render(batch, parentAlpha); + super.draw(batch, parentAlpha); + } } diff --git a/core/src/zero1hd/rhythmbullet/ui/pages/MusicSelectionPage.java b/core/src/zero1hd/rhythmbullet/ui/pages/MusicSelectionPage.java index fa3e96e..61557f1 100755 --- a/core/src/zero1hd/rhythmbullet/ui/pages/MusicSelectionPage.java +++ b/core/src/zero1hd/rhythmbullet/ui/pages/MusicSelectionPage.java @@ -1,159 +1,95 @@ package zero1hd.rhythmbullet.ui.pages; -import java.io.File; -import java.io.FilenameFilter; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Preferences; +import com.badlogic.gdx.assets.AssetManager; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.scenes.scene2d.Actor; 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.TextButton; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.badlogic.gdx.utils.Array; -import zero1hd.rhythmbullet.RhythmBullet; -import zero1hd.rhythmbullet.audio.AudioInfo; +import zero1hd.rhythmbullet.audio.SongInfo; +import zero1hd.rhythmbullet.audio.SongList; import zero1hd.rhythmbullet.ui.builders.MusicSelectable; -import zero1hd.rhythmbullet.ui.windows.LoadingWindow; -import zero1hd.rhythmbullet.ui.windows.NoticeWindow; import zero1hd.rhythmbullet.util.MiniEvents; public class MusicSelectionPage extends Page { - private volatile Table musicChoices; Preferences musicFileAnnotation; - private RhythmBullet core; - private volatile ScrollPane musicChoiceScroller; - private volatile LoadingWindow loadingWindow; - protected volatile boolean cancel; + private SongList songList; + private Array selectables; + private Table songTable; + private ScrollPane scrollbar; private TextButton back; 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"); - - back = new TextButton("Back", core.getDefaultSkin()); + this.assets = assetManager; + 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.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { miniSender.send(MiniEvents.BACK); - cancel = true; } }); 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(); } @Override public void act(float delta) { - back.toFront(); 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() { return selectedMusic; } - public AudioInfo getSelectedMusicInfo() { + public SongInfo getSelectedMusicInfo() { return selectedMusicInfo; } - @Override - public synchronized void addActor(Actor actor) { - super.addActor(actor); + public void refresh() { + for (int i = 0; i < songList.getAmountOfSongs(); i++) { + 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(); + }); + } + }); } } diff --git a/core/src/zero1hd/rhythmbullet/ui/pages/OptionsPage.java b/core/src/zero1hd/rhythmbullet/ui/pages/OptionsPage.java index a65700d..9e31f3d 100755 --- a/core/src/zero1hd/rhythmbullet/ui/pages/OptionsPage.java +++ b/core/src/zero1hd/rhythmbullet/ui/pages/OptionsPage.java @@ -17,6 +17,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextField; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import zero1hd.rhythmbullet.RhythmBullet; +import zero1hd.rhythmbullet.audio.SongList; import zero1hd.rhythmbullet.screens.CreativeScreen; import zero1hd.rhythmbullet.screens.MainMenu; @@ -26,7 +27,7 @@ public class OptionsPage extends Page { private ProgressBar fxVolSlider; 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(); 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()); if (debugCodeField.getText().equals("creative")) { 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); diff --git a/core/src/zero1hd/rhythmbullet/ui/windows/MusicSelector.java b/core/src/zero1hd/rhythmbullet/ui/windows/MusicSelector.java index a512178..e18c080 100755 --- a/core/src/zero1hd/rhythmbullet/ui/windows/MusicSelector.java +++ b/core/src/zero1hd/rhythmbullet/ui/windows/MusicSelector.java @@ -11,8 +11,8 @@ import com.badlogic.gdx.scenes.scene2d.ui.Window; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.utils.Array; -import zero1hd.rhythmbullet.audio.Audio; import zero1hd.rhythmbullet.audio.CoreMusicInfo; +import zero1hd.rhythmbullet.audio.SongList; import zero1hd.rhythmbullet.util.MiniEvents; import zero1hd.rhythmbullet.util.MiniSender; @@ -22,23 +22,23 @@ public class MusicSelector extends Window { FileHandle selectedMusic; Array fileNames; private List musicList; - private String path; private ScrollPane listScroller; + private SongList songList; 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"); - this.path = path; padTop(25f); padLeft(5f); padRight(5f); + this.songList = songList; miniSender = new MiniSender(); setSize(Gdx.graphics.getWidth()*0.5f, Gdx.graphics.getHeight()*0.5f); fileNames = new Array<>(); - musicList = new List(skin, listStyle); + musicList = new List(skin, "default"); TextButton confirmButton = new TextButton("confirm", skin, "window"); confirmButton.addListener(new ChangeListener() { @@ -71,15 +71,8 @@ public class MusicSelector extends Window { } public void refresh() { - fileNames.clear(); - FileHandle[] musicListArray = Gdx.files.absolute(path).list(); - 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); + songList.refresh(); + musicList.setItems(songList.getSongList()); } @@ -97,7 +90,7 @@ public class MusicSelector extends Window { public CoreMusicInfo getSelectedMusic() { if (selectedMusic != null) { - return Audio.getAudioData(selectedMusic); + return songList.getAudioData(selectedMusic); } else { return null; }