diff --git a/android/assets/uiskin.atlas b/android/assets/uiskin.atlas index 810c86d..d6ff806 100755 --- a/android/assets/uiskin.atlas +++ b/android/assets/uiskin.atlas @@ -385,4 +385,12 @@ rect-disabled split: 4, 4, 4, 4 orig: 14, 14 offset: 0, 0 + index: -1 +side-bars + rotate: false + xy: 221, 35 + size: 5, 14 + split: 2, 2, 0, 0 + orig: 5, 14 + offset: 0, 0 index: -1 \ No newline at end of file diff --git a/android/assets/uiskin.png b/android/assets/uiskin.png index 67b53ba..6a02a04 100755 Binary files a/android/assets/uiskin.png and b/android/assets/uiskin.png differ diff --git a/core/src/zero1hd/rhythmbullet/audio/Mp3Manager.java b/core/src/zero1hd/rhythmbullet/audio/Mp3Manager.java index 1ccae0a..e88a89b 100755 --- a/core/src/zero1hd/rhythmbullet/audio/Mp3Manager.java +++ b/core/src/zero1hd/rhythmbullet/audio/Mp3Manager.java @@ -47,9 +47,10 @@ public class Mp3Manager implements MusicManager { private ExecutorService exec; + private String basicSongName; public Mp3Manager(FileHandle audioFile) { lock = new ReentrantLock(); - + this.basicSongName = audioFile.name(); exec = Executors.newSingleThreadExecutor(); exec.submit(() -> { lock.lock(); @@ -230,11 +231,23 @@ public class Mp3Manager implements MusicManager { @Override public boolean isFinishedLoading() { - try { - return lock.tryLock(0, TimeUnit.SECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - return false; + if (lock.isHeldByCurrentThread()) { + return true; + } else { + try { + if (lock.tryLock(0, TimeUnit.SECONDS)) { + return true; + } else { + return false; + } + } catch (InterruptedException e) { + return false; + } } } + + @Override + public String getBasicSongName() { + return basicSongName; + } } diff --git a/core/src/zero1hd/rhythmbullet/audio/MusicManager.java b/core/src/zero1hd/rhythmbullet/audio/MusicManager.java index ed6c10a..f421e8b 100755 --- a/core/src/zero1hd/rhythmbullet/audio/MusicManager.java +++ b/core/src/zero1hd/rhythmbullet/audio/MusicManager.java @@ -74,4 +74,11 @@ public interface MusicManager extends Disposable { * @return whether its done loading */ public boolean isFinishedLoading(); + + /** + * Basic song name is the name of the file of the song, meaning we do not check tags for proper song name. + * Thats left up to the song info object. + * @return basic song name + */ + public String getBasicSongName(); } diff --git a/core/src/zero1hd/rhythmbullet/audio/SongInfo.java b/core/src/zero1hd/rhythmbullet/audio/SongInfo.java index b5ecb7c..7494e8e 100755 --- a/core/src/zero1hd/rhythmbullet/audio/SongInfo.java +++ b/core/src/zero1hd/rhythmbullet/audio/SongInfo.java @@ -32,12 +32,15 @@ public class SongInfo implements Disposable { private FileHandle musicFile; private Preferences musicAnnotation; - public SongInfo(FileHandle musicFile, Preferences musicData) { this.musicFile = musicFile; this.musicAnnotation = musicData; } + /** + * loads the information for this song. + * should be called in non-render thread as is blocking and depends on IO speed. + */ public void loadInfo() { if (musicFile.extension().toLowerCase().equals("mp3")) { MP3File mp3File; diff --git a/core/src/zero1hd/rhythmbullet/audio/SongListController.java b/core/src/zero1hd/rhythmbullet/audio/SongListController.java index 66321b0..7861504 100755 --- a/core/src/zero1hd/rhythmbullet/audio/SongListController.java +++ b/core/src/zero1hd/rhythmbullet/audio/SongListController.java @@ -30,8 +30,8 @@ public class SongListController implements OnCompletionListener { this.prefs = prefs; listeners = new Array<>(); this.songList = songList; - changeSong(); rand = new Random(); + changeSong(); } public void play() { @@ -105,7 +105,11 @@ public class SongListController implements OnCompletionListener { } if (shuffle) { - currentPlaybackID = rand.nextInt(songList.getAmountOfSongs()); + if (songList.getAmountOfSongs() == 0) { + currentPlaybackID = 0; + } else { + currentPlaybackID = rand.nextInt(songList.getAmountOfSongs()); + } } else { if (currentPlaybackID > songList.getAmountOfSongs() -1) { currentPlaybackID = 0; diff --git a/core/src/zero1hd/rhythmbullet/audio/WAVManager.java b/core/src/zero1hd/rhythmbullet/audio/WAVManager.java index 399704e..bde92a3 100755 --- a/core/src/zero1hd/rhythmbullet/audio/WAVManager.java +++ b/core/src/zero1hd/rhythmbullet/audio/WAVManager.java @@ -20,7 +20,9 @@ public class WAVManager implements MusicManager { private Music playbackMusic; WavDecoder decoder; + private String basicSongName; public WAVManager(FileHandle file) { + basicSongName = file.name(); try { decoder = new WavDecoder(file); } catch (InvalidParameterException | IOException e) { @@ -127,4 +129,9 @@ public class WAVManager implements MusicManager { public boolean isFinishedLoading() { return true; } + + @Override + public String getBasicSongName() { + return basicSongName; + } } diff --git a/core/src/zero1hd/rhythmbullet/audio/visualizer/VisualizerCore.java b/core/src/zero1hd/rhythmbullet/audio/visualizer/VisualizerCore.java index 2b92d2b..c767d79 100755 --- a/core/src/zero1hd/rhythmbullet/audio/visualizer/VisualizerCore.java +++ b/core/src/zero1hd/rhythmbullet/audio/visualizer/VisualizerCore.java @@ -29,12 +29,14 @@ public class VisualizerCore implements Disposable { public void calculate() { if (mm != null) { mm.playbackIndexUpdate(); + lock.lock(); while (calc && mm.isPlaying() && mm.getPlaybackIndexPosition() > mm.getCurrentReadWindowIndex()) { - lock.lock(); mm.readSamples(audioPCM); - fft.realForward(audioPCM); - lock.unlock(); + if (mm.getPlaybackIndexPosition() == mm.getCurrentReadWindowIndex()) { + fft.realForward(audioPCM); + } } + lock.unlock(); } } @@ -90,4 +92,7 @@ public class VisualizerCore implements Disposable { return height; } + public MusicManager getMm() { + return mm; + } } diff --git a/core/src/zero1hd/rhythmbullet/graphics/ui/components/MusicControls.java b/core/src/zero1hd/rhythmbullet/graphics/ui/components/MusicControls.java index 8b6a512..919cede 100755 --- a/core/src/zero1hd/rhythmbullet/graphics/ui/components/MusicControls.java +++ b/core/src/zero1hd/rhythmbullet/graphics/ui/components/MusicControls.java @@ -98,6 +98,7 @@ public class MusicControls extends HorizontalGroup { if (disableTimer <= 0) { forward.setDisabled(false); reverse.setDisabled(false); + disableTimer = 0; } } super.act(delta); diff --git a/core/src/zero1hd/rhythmbullet/graphics/ui/components/MusicSelectable.java b/core/src/zero1hd/rhythmbullet/graphics/ui/components/MusicSelectable.java index fa5e4e6..948cd3a 100755 --- a/core/src/zero1hd/rhythmbullet/graphics/ui/components/MusicSelectable.java +++ b/core/src/zero1hd/rhythmbullet/graphics/ui/components/MusicSelectable.java @@ -41,7 +41,7 @@ public class MusicSelectable extends Widget implements Disposable { imageIcon = new Image(albumCover); table.add(imageIcon); - displayName = new ScrollText(musicFile.name(), skin, true); + displayName = new ScrollText(musicFile.name(), null, skin, true, false); table.add(displayName); table.row(); @@ -53,7 +53,11 @@ public class MusicSelectable extends Widget implements Disposable { table.defaults().pad(10f); } - + + /** + * updates the UI side of information. + * needs to be called in thread with gl context. + */ public void updateInfo() { durationLabel.setText("Runtime: " + ((songInfo.getDurationInSeconds() / 60 < 1) ? "00" : songInfo.getDurationInSeconds() / 60) + ":" diff --git a/core/src/zero1hd/rhythmbullet/graphics/ui/components/ScrollText.java b/core/src/zero1hd/rhythmbullet/graphics/ui/components/ScrollText.java index ec13b7d..bb0ab24 100755 --- a/core/src/zero1hd/rhythmbullet/graphics/ui/components/ScrollText.java +++ b/core/src/zero1hd/rhythmbullet/graphics/ui/components/ScrollText.java @@ -1,9 +1,11 @@ package zero1hd.rhythmbullet.graphics.ui.components; +import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.GlyphLayout; +import com.badlogic.gdx.graphics.g2d.NinePatch; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; @@ -18,63 +20,46 @@ public class ScrollText extends Widget { Rectangle clipBounds = new Rectangle(); GlyphLayout gLayout; - String text; + String text1; + String text2; BitmapFont font; - private float fontHeight; - private float fontWidth; + private float textHeight; + private float text1Width; + private float text2Width; private boolean scrollOnHover; private boolean scroll; - private float textOffset; + private float text1Offset, text2Offset; + + private NinePatch background; private Vector2 coords; - public ScrollText(String text, Skin skin, boolean scrollOnHover) { + public ScrollText(String text, String text2, Skin skin, boolean scrollOnHover, boolean useBackground) { super(); - setName(text); - this.scrollOnHover = scrollOnHover; - - this.text = text; font = skin.getFont("default-font"); - font.setColor(skin.getColor("default")); - gLayout = new GlyphLayout(font, text); - - fontHeight = gLayout.height; - fontWidth = gLayout.width; - - coords = new Vector2(); - - addListener(new ClickListener() { - @Override - public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) { - scroll = true; - super.enter(event, x, y, pointer, fromActor); - } - - @Override - public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) { - scroll = false; - super.exit(event, x, y, pointer, toActor); - } - - @Override - public void clicked(InputEvent event, float x, float y) { - } - }); + init(text, text2, skin, scrollOnHover, useBackground); } - public ScrollText(String text, Skin skin, String fontName, Color color, boolean scrollOnHover) { + public ScrollText(String text, String text2, Skin skin, String fontName, Color color, boolean scrollOnHover, boolean useBackground) { super(); - setName(text); - this.scrollOnHover = scrollOnHover; - - this.text = text; font = skin.getFont(fontName); font.setColor(color); - gLayout = new GlyphLayout(font, text); + init(text, text2, skin, scrollOnHover, useBackground); + } + + private void init(String text1, String text2, Skin skin, boolean scrollOnHover, boolean useBackground) { + setName(text1); + if (useBackground) { + this.background = skin.getPatch("side-bars"); + } - fontHeight = gLayout.height; - fontWidth = gLayout.width; + this.scrollOnHover = scrollOnHover; + + if (text1 == null) { + text1 = ""; + } + setText(text1, text2); coords = new Vector2(); @@ -98,55 +83,74 @@ public class ScrollText extends Widget { } public float getFontHeight() { - return fontHeight; + return textHeight; } public float getFontWidth() { - return fontWidth; + return text1Width; } @Override public void layout() { - setHeight(fontHeight+4); - clipBounds.setSize(getWidth(), getHeight()*1.5f); + if (getHeight() < (textHeight+4)) { + setHeight(textHeight + 4); + } + clipBounds.setSize(getWidth()-1, getHeight()*1.5f); super.layout(); } @Override public void act(float delta) { - if (fontWidth > clipBounds.getWidth()) { + validate(); + if (text1Width + text2Width > clipBounds.getWidth()) { if (scrollOnHover) { - if ((int) textOffset != 0 || scroll) { - if (textOffset < -fontWidth) { - textOffset = clipBounds.getWidth(); - } - textOffset -= 60*delta; + if (scroll) { + scroll(delta); } } else { - if (textOffset < -fontWidth) { - textOffset = clipBounds.getWidth(); - } - textOffset -= 60*delta; + scroll(delta); } } super.act(delta); } + public void scroll(float delta) { + if (text1Offset >= -text1Width) { + text1Offset -= 60*delta; + + + if ((text1Offset < - Math.abs((text1Width - clipBounds.getWidth())) - 50) || text2Offset != clipBounds.getWidth()) { + text2Offset -= 60*delta; + if (text2Offset <= -text2Width) { + text2Offset = clipBounds.getWidth(); + } + } + + } else { + text2Offset -= 60*delta; + if (text2Offset < - Math.abs((text2Width - clipBounds.getWidth())) - 50) { + text1Offset = clipBounds.getWidth(); + } + } + } @Override public void draw(Batch batch, float parentAlpha) { - + if (background != null) { + background.draw(batch, getX(), getY(), getWidth(), getHeight()); + } coords.x = getX(); coords.y = getY(); - clipBounds.setX(coords.x); + clipBounds.setX(coords.x+1); clipBounds.setY(coords.y - 0.5f*getHeight()); getStage().calculateScissors(clipBounds, scissors); batch.flush(); if (ScissorStack.pushScissors(scissors)) { - font.draw(batch, text, coords.x + textOffset, coords.y + getFontHeight()); + font.draw(batch, text1, coords.x + text1Offset, coords.y + getFontHeight() + getHeight()/4f); + font.draw(batch, text2, coords.x + text2Offset, coords.y + getFontHeight() + getHeight()/4f); batch.flush(); ScissorStack.popScissors(); }; @@ -154,6 +158,30 @@ public class ScrollText extends Widget { @Override public float getMinHeight() { - return fontHeight; + return textHeight; + } + + /** + * Sets the two strings that will be scrolling. + * @param text1 cannot be null. + * @param text2 can be null. + */ + public void setText(String text1, String text2) { + this.text1 = text1; + gLayout = new GlyphLayout(font, text1); + text1Width = gLayout.width; + textHeight = gLayout.height; + text2Offset = clipBounds.getWidth(); + if (text1Width < clipBounds.getWidth()) { + text1Offset = (clipBounds.getWidth()-text1Width)/2f; + } + if (text2 != null) { + this.text2 = text2; + gLayout = new GlyphLayout(font, text2); + text2Width = gLayout.width; + } else { + this.text2 = text1; + this.text2Width = text1Width; + } } } diff --git a/core/src/zero1hd/rhythmbullet/graphics/ui/components/TitleBarVisualizer.java b/core/src/zero1hd/rhythmbullet/graphics/ui/components/TitleBarVisualizer.java index 416c0d2..2673a0c 100755 --- a/core/src/zero1hd/rhythmbullet/graphics/ui/components/TitleBarVisualizer.java +++ b/core/src/zero1hd/rhythmbullet/graphics/ui/components/TitleBarVisualizer.java @@ -33,7 +33,7 @@ public class TitleBarVisualizer extends Group implements Disposable { public TitleBarVisualizer(AssetManager assets) { if (assets == null) throw new NullPointerException("TitleBarVisualizer requires assets manager... ITS NULL YOU FOOL"); visual = new Visualizer(); - visual.getVis().setSpaceBetweenBars(visual.getVis().getBarWidth()-2); + visual.getVis().setSpaceBetweenBars(visual.getVis().getBarWidth()- 2); addActor(visual); setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()*0.2f); @@ -85,11 +85,10 @@ public class TitleBarVisualizer extends Group implements Disposable { @Override public void act(float delta) { if (!lastEffect) { - if (visual.getVis().getCurrentAvg() > visual.getVis().getMaxAvgHeight()*0.55f) { + if (visual.getVis().getMm() != null && visual.getVis().getMm().isPlaying() && visual.getVis().getCurrentAvg() > visual.getVis().getMaxAvgHeight()*0.55f) { PooledEffect effect = beatEffectPool.obtain(); effect.setPosition(0, 0); effects.add(effect); - lastEffect = true; } } else { diff --git a/core/src/zero1hd/rhythmbullet/graphics/ui/components/Visualizer.java b/core/src/zero1hd/rhythmbullet/graphics/ui/components/Visualizer.java index 48ac3e0..b3e0969 100755 --- a/core/src/zero1hd/rhythmbullet/graphics/ui/components/Visualizer.java +++ b/core/src/zero1hd/rhythmbullet/graphics/ui/components/Visualizer.java @@ -70,8 +70,6 @@ public class Visualizer extends Widget { } public void setUpdatePositioning(boolean updatePositioning) { - updateVisualPosition(); - vis.setxPos(((vis.getWidth() - vis.getActualWidth())/2f)); updateVisualPosition(); this.updatePositioning = updatePositioning; } @@ -79,6 +77,9 @@ public class Visualizer extends Widget { public void updateVisualPosition() { setVisualizerPosProp(); vis.updatePositionInfo(); + vis.setxPos(((vis.getWidth() - vis.getActualWidth())/2f)); + Gdx.app.debug("Visualizer", "currently offseting visualizer by (px): " + vis.getxPos()); + vis.updatePositionInfo(); } public boolean isUpdatePositioning() { diff --git a/core/src/zero1hd/rhythmbullet/graphics/ui/pages/AnalyzePage.java b/core/src/zero1hd/rhythmbullet/graphics/ui/pages/AnalyzePage.java index 7feeadd..a3930c0 100755 --- a/core/src/zero1hd/rhythmbullet/graphics/ui/pages/AnalyzePage.java +++ b/core/src/zero1hd/rhythmbullet/graphics/ui/pages/AnalyzePage.java @@ -201,7 +201,7 @@ public class AnalyzePage extends Page implements MiniListener, Disposable { audioAnalyzer.sender.addListener(this); - songInfo.add(new ScrollText(audioInfo.getSongName(), skin, true)).expandX().fillX().spaceBottom(20f); + songInfo.add(new ScrollText(audioInfo.getSongName(), null, skin, true, false)).expandX().fillX().spaceBottom(20f); for (int i = 0; i < info.length; i++) { info[i].setColor(1f, 1f, 1f, 0f); diff --git a/core/src/zero1hd/rhythmbullet/graphics/ui/pages/MainPage.java b/core/src/zero1hd/rhythmbullet/graphics/ui/pages/MainPage.java index f2a9c78..83ac1b2 100755 --- a/core/src/zero1hd/rhythmbullet/graphics/ui/pages/MainPage.java +++ b/core/src/zero1hd/rhythmbullet/graphics/ui/pages/MainPage.java @@ -15,6 +15,7 @@ import zero1hd.rhythmbullet.audio.MusicManager; import zero1hd.rhythmbullet.audio.SongListController; import zero1hd.rhythmbullet.events.OnDifferentSongListener; import zero1hd.rhythmbullet.graphics.ui.components.MusicControls; +import zero1hd.rhythmbullet.graphics.ui.components.ScrollText; import zero1hd.rhythmbullet.graphics.ui.components.TitleBarVisualizer; public class MainPage extends Page implements OnDifferentSongListener { @@ -28,13 +29,13 @@ public class MainPage extends Page implements OnDifferentSongListener { private TextButton quitButton; private MusicControls musicControls; + + private ScrollText scrollText; public MainPage(RhythmBullet core, Vector3 targetPosition, SongListController sc) { this.sc = sc; titleBar = new TitleBarVisualizer(core.getAssetManager()); addActor(titleBar); - - titleBar.getHvisual().setMM(sc.getCurrentSong()); sc.addOnDifferentSongListener(this); versionLabel = new Label("Version: " + RhythmBullet.VERSION, core.getDefaultSkin(), "sub-font", @@ -81,7 +82,17 @@ public class MainPage extends Page implements OnDifferentSongListener { musicControls = new MusicControls(core.getDefaultSkin(), sc); musicControls.setPosition((getWidth()-musicControls.getMinWidth() - 20f), getHeight()-musicControls.getMinHeight()); + musicControls.invalidate(); addActor(musicControls); + + scrollText = new ScrollText("...", "...", core.getDefaultSkin(), false, true); + scrollText.setWidth(0.5f*getWidth()); + scrollText.setHeight(musicControls.getMinHeight()); + scrollText.setPosition((getWidth() - scrollText.getWidth())/2f, musicControls.getY() - 22f); + scrollText.invalidate(); + addActor(scrollText); + + onDifferentSong(sc.getCurrentSong()); } @Override @@ -97,6 +108,7 @@ public class MainPage extends Page implements OnDifferentSongListener { @Override public void onDifferentSong(MusicManager mdp) { titleBar.getHvisual().setMM(mdp); + scrollText.setText(mdp.getBasicSongName(), null); } @Override