From 0dce05050a6ccf6da3324b9b2ee992578b70ef4e Mon Sep 17 00:00:00 2001 From: Recrown Date: Sun, 22 Jul 2018 12:35:08 -0500 Subject: [PATCH] Restructuring starting from the launcher up to obtaining PCM data from the audio backend is complete but untested. --- core/src/zero1hd/rhythmbullet/AssetPack.java | 45 +++ .../zero1hd/rhythmbullet/InitialScreen.java | 7 + .../zero1hd/rhythmbullet/RhythmBullet.java | 350 +++++------------- .../audio/AudioProcessorFactory.java | 12 + .../audio/MinimalAudioHeader.java | 37 ++ .../rhythmbullet/audio/MusicController.java | 223 +++++++++++ .../zero1hd/rhythmbullet/audio/MusicList.java | 135 +++++++ .../audio/MusicMetadataController.java | 102 +++++ .../audio/RhythmBulletMetadata.java | 29 -- .../audio/{ => metadata}/AudioMetadata.java | 2 +- .../audio/{ => metadata}/MP3Metadata.java | 2 +- .../audio/{ => metadata}/WAVMetadata.java | 2 +- .../audio/processor/WAVAudioProcessor.java | 16 +- .../visualizer/HorizontalVisualizer.java | 1 - ...sizeScreen.java => ResizeReadyScreen.java} | 2 +- .../desktop/DesktopAssetPack.java | 224 +++++++++++ .../rhythmbullet/desktop/DesktopLauncher.java | 8 +- .../desktop/audio/MusicInfoController.java | 64 ---- .../rhythmbullet/desktop/audio/MusicList.java | 129 ------- .../desktop/audio/MusicListController.java | 154 -------- .../desktop/audio/map/RhythmMapAlgorithm.java | 73 ---- .../DesktopAudioProcessorFactory.java | 13 + .../audio/visualizer/DesktopVisualizer.java | 163 +++++--- .../ui/components/GraphicsOptions.java | 4 +- .../HorizontalVisualizerWidget.java | 22 +- .../graphics/ui/components/MusicControls.java | 4 +- .../graphics/ui/pages/AnalysisPage.java | 2 +- .../ui/pages/GraphicsOptionsPage.java | 4 +- .../desktop/graphics/ui/pages/MainPage.java | 44 +-- .../graphics/ui/pages/MusicSelectionPage.java | 19 +- .../graphics/ui/pages/OptionsPage.java | 34 +- .../{MainMenuScreen.java => MainScreen.java} | 52 ++- .../desktop/screens/SplashScreen.java | 44 +-- 33 files changed, 1114 insertions(+), 908 deletions(-) create mode 100755 core/src/zero1hd/rhythmbullet/AssetPack.java create mode 100755 core/src/zero1hd/rhythmbullet/InitialScreen.java create mode 100755 core/src/zero1hd/rhythmbullet/audio/AudioProcessorFactory.java create mode 100755 core/src/zero1hd/rhythmbullet/audio/MinimalAudioHeader.java create mode 100755 core/src/zero1hd/rhythmbullet/audio/MusicController.java create mode 100755 core/src/zero1hd/rhythmbullet/audio/MusicList.java create mode 100755 core/src/zero1hd/rhythmbullet/audio/MusicMetadataController.java delete mode 100755 core/src/zero1hd/rhythmbullet/audio/RhythmBulletMetadata.java rename core/src/zero1hd/rhythmbullet/audio/{ => metadata}/AudioMetadata.java (90%) rename core/src/zero1hd/rhythmbullet/audio/{ => metadata}/MP3Metadata.java (94%) rename core/src/zero1hd/rhythmbullet/audio/{ => metadata}/WAVMetadata.java (94%) rename core/src/zero1hd/rhythmbullet/util/{AdvancedResizeScreen.java => ResizeReadyScreen.java} (81%) create mode 100755 desktop/src/zero1hd/rhythmbullet/desktop/DesktopAssetPack.java delete mode 100755 desktop/src/zero1hd/rhythmbullet/desktop/audio/MusicInfoController.java delete mode 100755 desktop/src/zero1hd/rhythmbullet/desktop/audio/MusicList.java delete mode 100755 desktop/src/zero1hd/rhythmbullet/desktop/audio/MusicListController.java delete mode 100755 desktop/src/zero1hd/rhythmbullet/desktop/audio/map/RhythmMapAlgorithm.java create mode 100755 desktop/src/zero1hd/rhythmbullet/desktop/audio/processor/DesktopAudioProcessorFactory.java rename desktop/src/zero1hd/rhythmbullet/desktop/screens/{MainMenuScreen.java => MainScreen.java} (88%) diff --git a/core/src/zero1hd/rhythmbullet/AssetPack.java b/core/src/zero1hd/rhythmbullet/AssetPack.java new file mode 100755 index 0000000..a5cfb97 --- /dev/null +++ b/core/src/zero1hd/rhythmbullet/AssetPack.java @@ -0,0 +1,45 @@ +package zero1hd.rhythmbullet; + +import com.badlogic.gdx.assets.AssetManager; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.utils.Disposable; + +public interface AssetPack extends Disposable { + + /** + * Called right after the game instance is created and passed to LWJGL. This method is called once for you to instantiate things for later use but require Libgdx functions. + */ + public void initiateResources(); + + /** + * Game manager calls this when it needs to load textures. + */ + public void queueTextures(AssetManager assetManager); + + /** + * Game manager calls this when it needs to load sound effects. + */ + public void queueSFX(AssetManager assetManager); + + /** + * Game manager calls this when it needs to load particles. + */ + public void queueParticles(AssetManager assetManager); + + /** + * Game manager calls when it needs to load particles. Usually called after textures are loaded since the skin requires the other assets. + * @param skin the skin object to set up. + */ + public void setupSkin(Skin skin); + + /** + * Game manager calls when it needs the fonts to be generated. Usually called right before setting up the skin itself since items in the skin need fonts. + */ + public void generateFonts(Skin skin); + + /** + * Game manager calls this once all assets are loaded. This function should be used to make some in-code adjustments to assets that will be consistent throughout the game for that run. + * @param assetManager gives you access to the assets to modify. + */ + public void complete(AssetManager assetManager); +} diff --git a/core/src/zero1hd/rhythmbullet/InitialScreen.java b/core/src/zero1hd/rhythmbullet/InitialScreen.java new file mode 100755 index 0000000..5babb5e --- /dev/null +++ b/core/src/zero1hd/rhythmbullet/InitialScreen.java @@ -0,0 +1,7 @@ +package zero1hd.rhythmbullet; + +import com.badlogic.gdx.Screen; + +public interface InitialScreen { + public Screen createMainScreen(RhythmBullet game); +} diff --git a/core/src/zero1hd/rhythmbullet/RhythmBullet.java b/core/src/zero1hd/rhythmbullet/RhythmBullet.java index 2241b38..3a2aae0 100755 --- a/core/src/zero1hd/rhythmbullet/RhythmBullet.java +++ b/core/src/zero1hd/rhythmbullet/RhythmBullet.java @@ -13,28 +13,14 @@ import com.badlogic.gdx.assets.loaders.TextureLoader; import com.badlogic.gdx.assets.loaders.resolvers.InternalFileHandleResolver; import com.badlogic.gdx.assets.loaders.resolvers.ResolutionFileResolver.Resolution; import com.badlogic.gdx.audio.Sound; -import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.ParticleEffect; 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.CheckBox.CheckBoxStyle; -import com.badlogic.gdx.scenes.scene2d.ui.ImageButton.ImageButtonStyle; -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.ScrollPane.ScrollPaneStyle; -import com.badlogic.gdx.scenes.scene2d.ui.SelectBox.SelectBoxStyle; import com.badlogic.gdx.scenes.scene2d.ui.Skin; -import com.badlogic.gdx.scenes.scene2d.ui.Slider.SliderStyle; -import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle; -import com.badlogic.gdx.scenes.scene2d.ui.TextField.TextFieldStyle; -import com.badlogic.gdx.scenes.scene2d.ui.Window.WindowStyle; import zero1hd.rhythmbullet.util.GenericFileTypeHandler; import zero1hd.rhythmbullet.util.RoundingResolutionHandler; -import zero1hd.rhythmbullet.util.AdvancedResizeScreen; +import zero1hd.rhythmbullet.util.ResizeReadyScreen; public class RhythmBullet extends Game { @@ -42,34 +28,37 @@ public class RhythmBullet extends Game { public static final int WORLD_HEIGHT = 48; public static final int SPAWN_CIRCLE_RADIUS = 6; public static int pixels_per_unit; - private boolean initComplete = false; + private boolean initiated; private boolean resizing; private int screenWidth, screenHeight; public static final String VERSION = "(0.1)R1-PreAlpha"; private AssetManager assetManager = new AssetManager(); - private Skin defaultSkin = new Skin(); - private FreeTypeFontGenerator default_fontGenerator; - private FreeTypeFontGenerator darktech_ldr_fontGenerator; + private Skin skin; TextureAtlas skinAtlas; private Preferences prefs; private RoundingResolutionHandler rRHandler; private Screen initialScreen; + private AssetPack assetPack; - public void setInitialScreen(Screen initialScreen) { + /** + * This should be called before passed to LWJGL. Setup for system-dependent items such as UI and assets. + * @param initialScreen the first screen to go to. + * @param assetPack the asset package to be used. + */ + public void setup(Screen initialScreen, AssetPack assetPack) { this.initialScreen = initialScreen; + this.assetPack = assetPack; } @Override public void create() { Gdx.app.setLogLevel(Application.LOG_DEBUG); - prefs = Gdx.app.getPreferences("RhythmBullet Preferences"); + setScreen(initialScreen); + + assetPack.initiateResources(); - if (getPrefs().getBoolean("fullscreen", true)) { - Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode()); - } else { - Gdx.graphics.setWindowedMode(getPrefs().getInteger("screen-width"), getPrefs().getInteger("screen-height")); - } + prefs = Gdx.app.getPreferences("RhythmBullet Preferences"); Resolution[] resolution = { new Resolution(1280, 720, "1280x720"), @@ -88,57 +77,68 @@ public class RhythmBullet extends Game { assetManager.setLoader(Texture.class, new TextureLoader(rRHandler)); assetManager.setLoader(ParticleEffect.class, new ParticleEffectLoader(genericFileFinder)); assetManager.setLoader(Sound.class, new SoundLoader(genericFileFinder)); - default_fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/Gasalt-Regular.ttf")); - darktech_ldr_fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/darktech_ldr.ttf")); - getrRHandler().setResolution(getPrefs().getInteger("screen-width"), getPrefs().getInteger("screen-height")); + rRHandler.setResolution(getPrefs().getInteger("screen-width"), getPrefs().getInteger("screen-height")); - queueAssets(); - setScreen(initialScreen); screenWidth = Gdx.graphics.getWidth(); screenHeight = Gdx.graphics.getHeight(); pixels_per_unit = (int) (Float.valueOf(screenHeight)/Float.valueOf(WORLD_HEIGHT)); - } - - public void checkAssetQueue() { - if (!initComplete) { - if (assetManager.update()) { - generateFonts(Gdx.graphics.getHeight()); - defineSkinStyles(); - setInitComplete(); - } - } - } - - public void checkResize() { - if (resizing) { - if (assetManager.update()) { - Gdx.app.debug("Resize", "Post transition is happening"); - resizing = false; - generateFonts(Gdx.graphics.getHeight()); - defineSkinStyles(); - assetManager.get("standard_thrust.p", ParticleEffect.class).flipY(); - ((AdvancedResizeScreen) getScreen()).postAssetLoad(); - } + + if (getPrefs().getBoolean("fullscreen", true)) { + Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode()); + } else { + Gdx.graphics.setWindowedMode(getPrefs().getInteger("screen-width"), getPrefs().getInteger("screen-height")); } } @Override public void render() { - checkResize(); checkAssetQueue(); super.render(); } + public boolean checkAssetQueue() { + if (assetManager.update()) { + if (skin != null) skin.dispose(); + skin = new Skin(); + skinAtlas = assetManager.get("uiskin.atlas", TextureAtlas.class); + getSkinSkin().addRegions(skinAtlas); + + assetPack.generateFonts(skin); + assetPack.setupSkin(skin); + assetPack.complete(assetManager); + + if (resizing) { + Gdx.app.debug("Resize", "Post resize is starting..."); + if (getScreen() instanceof ResizeReadyScreen) { + ((ResizeReadyScreen) getScreen()).postAssetLoad(); + } else { + throw new IllegalStateException("Cannot perform window resize on a screen that isn't using a resize ready screen."); + } + Gdx.app.debug("Resize", "Post resize has ended."); + + if (!initiated) { + setScreen(((InitialScreen) initialScreen).createMainScreen(this)); + initiated = true; + } + resizing = false; + } + return true; + } + return false; + } + + @Override public void setScreen(Screen screen) { - if (screen instanceof AdvancedResizeScreen) { - AdvancedResizeScreen advancedResizeScreen = (AdvancedResizeScreen) screen; + if (screen instanceof ResizeReadyScreen) { + ResizeReadyScreen advancedResizeScreen = (ResizeReadyScreen) screen; try { advancedResizeScreen.preAssetLoad(); } catch (NullPointerException cleanScreen) { + //Tried to perform pre-asset reload, but had uninitialized objects, meaning this is a new screen, or "clean" screen. } finally { advancedResizeScreen.postAssetLoad(); } @@ -146,235 +146,61 @@ public class RhythmBullet extends Game { super.setScreen(screen); } - @Override - public void dispose() { - Gdx.app.debug("Core", "disposing..."); - if (initComplete) { - skinAtlas.dispose(); - getDefaultSkin().dispose(); - default_fontGenerator.dispose(); - darktech_ldr_fontGenerator.dispose(); - assetManager.dispose(); - getScreen().dispose(); - } - super.dispose(); - } - @Override public void resize(int width, int height) { - Gdx.app.debug("RhythmBullet/resize", "Previous size:" + screenWidth + "x" + screenHeight + " new size: " + width + "x" + height); + Gdx.app.debug("RhythmBullet/resize", "Current size:" + screenWidth + "x" + screenHeight + " new size: " + width + "x" + height); if (width != screenWidth || height != screenHeight) { screenWidth = Gdx.graphics.getWidth(); screenHeight = Gdx.graphics.getHeight(); pixels_per_unit = (int) (Float.valueOf(screenHeight)/Float.valueOf(WORLD_HEIGHT)); - - if (initComplete) { - Gdx.app.debug("Resize", "Pre-transition is happening. Using resolution " + width + "x" + height); - rRHandler.setResolution(width, height); - ((AdvancedResizeScreen) getScreen()).preAssetLoad(); - assetManager.clear(); - prefs.putInteger("screen-width", width); - prefs.putInteger("screen-height", height); - prefs.flush(); - resizing = true; - queueAssets(); + Gdx.app.debug("Resize", "Pre-resize is happening. Resizing to " + width + "x" + height); + rRHandler.setResolution(width, height); + if (getScreen() instanceof ResizeReadyScreen) { + ((ResizeReadyScreen) getScreen()).preAssetLoad(); + } else { + throw new IllegalStateException("Cannot perform window resize on a screen that isn't using a resize ready screen."); } + prefs.putInteger("screen-width", width); + prefs.putInteger("screen-height", height); + prefs.flush(); + resizing = true; + assetManager.clear(); + queueAssets(); } super.resize(width, height); } - public int fontScale(float fontSize, int height) { - int size = MathUtils.round(Gdx.graphics.getDensity()*(fontSize*height)); - if (size >= 200) { - size = 200; - } - return size; + public void queueAssets() { + assetPack.queueTextures(assetManager); + assetPack.queueSFX(assetManager); + assetPack.queueParticles(assetManager); } public AssetManager getAssetManager() { return assetManager; } - public Skin getDefaultSkin() { - return defaultSkin; + public Skin getSkinSkin() { + return skin; } public Preferences getPrefs() { return prefs; } - - public void setInitComplete() { - initComplete = true; - } - - public boolean isInitComplete() { - return initComplete; - } - - public RoundingResolutionHandler getrRHandler() { - return rRHandler; - } - - public void queueAssets() { - assetManager.load("uiskin.atlas", TextureAtlas.class); - assetManager.load("Tech-Circle1.png", Texture.class); - assetManager.load("polyjet-standard.png", Texture.class); - assetManager.load("standard_thrust.p", ParticleEffect.class); - assetManager.load("keyboard.atlas", TextureAtlas.class); - assetManager.load("cybercircle3B.png", Texture.class); - assetManager.load("title.png", Texture.class); - assetManager.load("cybercircle1.png", Texture.class); - assetManager.load("defaultCover.png", Texture.class); - assetManager.load("teleport-cloak.p", ParticleEffect.class); - assetManager.load("pop_open.ogg", Sound.class); - assetManager.load("pop_close.ogg", Sound.class); - assetManager.load("laser.png", Texture.class); - assetManager.load("pellet.png", Texture.class); - assetManager.load("shard.png", Texture.class); - assetManager.load("bar.png", Texture.class); - assetManager.load("flake.png", Texture.class); - assetManager.load("void_circle.png", Texture.class); - assetManager.load("laser.ogg", Sound.class); - assetManager.load("explosion.ogg", Sound.class); - assetManager.load("disintegrate.ogg", Sound.class); - assetManager.load("explosion-s.p", ParticleEffect.class); - assetManager.load("beateffect.p", ParticleEffect.class); - assetManager.load("tpSelector.png", Texture.class); - assetManager.load("magic1.png", Texture.class); - assetManager.load("backgrounds/mainBG.png", Texture.class); - } - - public void generateFonts(final int height) { - defaultSkin = new Skin(); - Gdx.app.debug("Prelaunch Debug Info", "Generating fonts with screen height of " + height); - skinAtlas = assetManager.get("uiskin.atlas", TextureAtlas.class); - getDefaultSkin().addRegions(skinAtlas); - - getDefaultSkin().add("window-font", default_fontGenerator.generateFont(new FreeTypeFontParameter() { - { - size = 18; - } - })); - getDefaultSkin().add("sub-font", default_fontGenerator.generateFont(new FreeTypeFontParameter() { - { - size = fontScale(0.05f, height); - } - })); - getDefaultSkin().add("default-font", default_fontGenerator.generateFont(new FreeTypeFontParameter() { - { - size = fontScale(0.07f, height); - } - })); - getDefaultSkin().add("large-font", default_fontGenerator.generateFont(new FreeTypeFontParameter() { - { - size = fontScale(0.085f, height); - } - })); - getDefaultSkin().add("special-font", darktech_ldr_fontGenerator.generateFont(new FreeTypeFontParameter() { - { - size = fontScale(0.075f, height); - } - })); - } - - public void defineSkinStyles() { - getDefaultSkin().add("default", Color.WHITE); - getDefaultSkin().add("inverse", Color.BLACK); - - TextButtonStyle defaultTextButton = new TextButtonStyle(); - defaultTextButton.up = getDefaultSkin().getDrawable("rect"); - defaultTextButton.down = getDefaultSkin().getDrawable("rect-down"); - defaultTextButton.font = getDefaultSkin().getFont("default-font"); - defaultTextButton.fontColor = getDefaultSkin().getColor("default"); - defaultTextButton.disabled = getDefaultSkin().getDrawable("rect-disabled"); - getDefaultSkin().add("default", defaultTextButton); - - TextButtonStyle subTextbutton = new TextButtonStyle(defaultTextButton); - subTextbutton.font = getDefaultSkin().getFont("sub-font"); - getDefaultSkin().add("sub", subTextbutton); - - TextButtonStyle windowTextButton = new TextButtonStyle(defaultTextButton); - windowTextButton.font = getDefaultSkin().getFont("window-font"); - getDefaultSkin().add("window", windowTextButton); - - TextButtonStyle textButtonLeft = new TextButtonStyle(); - textButtonLeft.up = getDefaultSkin().getDrawable("left-button"); - textButtonLeft.down = getDefaultSkin().getDrawable("left-button-down"); - textButtonLeft.font = getDefaultSkin().getFont("default-font"); - textButtonLeft.fontColor = getDefaultSkin().getColor("default"); - getDefaultSkin().add("left", textButtonLeft); - - SliderStyle defaultSlider = new SliderStyle(getDefaultSkin().getDrawable("default-slider"), getDefaultSkin().getDrawable("default-slider-knob")); - getDefaultSkin().add("default-horizontal", defaultSlider); - - SliderStyle vertSlider = new SliderStyle(defaultSlider); - vertSlider.knob = getDefaultSkin().getDrawable("vertical-slider-knob"); - getDefaultSkin().add("default-vertical", vertSlider); - - LabelStyle defaultLabel = new LabelStyle(); - defaultLabel.font = getDefaultSkin().getFont("default-font"); - defaultLabel.fontColor = getDefaultSkin().getColor("default"); - getDefaultSkin().add("default", defaultLabel); - - TextFieldStyle defaultTextField = new TextFieldStyle(getDefaultSkin().getFont("sub-font"), getDefaultSkin().getColor("default"), getDefaultSkin().getDrawable("cursor"), getDefaultSkin().getDrawable("selection"), getDefaultSkin().getDrawable("textfield")); - getDefaultSkin().add("default", defaultTextField); - - TextFieldStyle uiTextField = new TextFieldStyle(defaultTextField); - uiTextField.font = getDefaultSkin().getFont("window-font"); - getDefaultSkin().add("ui", uiTextField); - - WindowStyle defaultWindow = new WindowStyle(getDefaultSkin().getFont("window-font"), getDefaultSkin().getColor("default"), getDefaultSkin().getDrawable("default-window")); - getDefaultSkin().add("default", defaultWindow); - - WindowStyle tintedWindow = new WindowStyle(defaultWindow); - tintedWindow.titleFontColor = getDefaultSkin().getColor("inverse"); - tintedWindow.background = getDefaultSkin().getDrawable("tinted-window"); - getDefaultSkin().add("tinted", tintedWindow); - - ListStyle defaultList = new ListStyle(getDefaultSkin().getFont("window-font"), getDefaultSkin().getColor("inverse"), getDefaultSkin().getColor("default"), getDefaultSkin().getDrawable("selection")); - getDefaultSkin().add("default", defaultList); - - ScrollPaneStyle defaultScrollPane = new ScrollPaneStyle(); - defaultScrollPane.vScroll = getDefaultSkin().getDrawable("default-scroll"); - defaultScrollPane.hScrollKnob = getDefaultSkin().getDrawable("default-round-large"); - defaultScrollPane.hScroll = getDefaultSkin().getDrawable("default-scroll"); - defaultScrollPane.vScrollKnob = getDefaultSkin().getDrawable("default-round-large"); - getDefaultSkin().add("default", defaultScrollPane); - - CheckBoxStyle defaultCheckBox = new CheckBoxStyle(getDefaultSkin().getDrawable("check-off"), getDefaultSkin().getDrawable("check-on"), getDefaultSkin().getFont("window-font"), getDefaultSkin().getColor("default")); - defaultCheckBox.checkboxOffDisabled = getDefaultSkin().getDrawable("check-disabled"); - getDefaultSkin().add("default", defaultCheckBox); - - SelectBoxStyle defaultSelectBox = new SelectBoxStyle(getDefaultSkin().getFont("default-font"), getDefaultSkin().getColor("default"), getDefaultSkin().getDrawable("default-select"), defaultScrollPane, defaultList); - getDefaultSkin().add("default", defaultSelectBox); - - Gdx.app.debug("Prelaunch Debug Info", "UI Skin has been defined."); - - CheckBoxStyle playButtonStyle = new CheckBoxStyle(defaultCheckBox); - playButtonStyle.checkboxOn = getDefaultSkin().getDrawable("play-down"); - playButtonStyle.checkboxOff = getDefaultSkin().getDrawable("play"); - getDefaultSkin().add("play-button", playButtonStyle); - - ImageButtonStyle pauseButtonStyle = new ImageButtonStyle(); - pauseButtonStyle.down = getDefaultSkin().getDrawable("pause-down"); - pauseButtonStyle.up = getDefaultSkin().getDrawable("pause"); - getDefaultSkin().add("pause-button", pauseButtonStyle); - - ImageButtonStyle fastForwardButtonStyle = new ImageButtonStyle(); - fastForwardButtonStyle.down = getDefaultSkin().getDrawable("fast-forward-down"); - fastForwardButtonStyle.up = getDefaultSkin().getDrawable("fast-forward"); - getDefaultSkin().add("fast-forward-button", fastForwardButtonStyle); - - ImageButtonStyle reverseButtonStyle = new ImageButtonStyle(); - reverseButtonStyle.down = getDefaultSkin().getDrawable("rewind-down"); - reverseButtonStyle.up = getDefaultSkin().getDrawable("rewind"); - getDefaultSkin().add("rewind-button", reverseButtonStyle); - - CheckBoxStyle shuffleButtonStyle = new CheckBoxStyle(defaultCheckBox); - shuffleButtonStyle.checkboxOff = getDefaultSkin().getDrawable("shuffle"); - shuffleButtonStyle.checkboxOn = getDefaultSkin().getDrawable("shuffle-down"); - getDefaultSkin().add("shuffle-button", shuffleButtonStyle); + @Override + public void dispose() { + Gdx.app.debug("Core", "disposing..."); + try { + skinAtlas.dispose(); + getSkinSkin().dispose(); + assetManager.dispose(); + getScreen().dispose(); + assetPack.dispose(); + } catch (NullPointerException npe) { + //Means the game was closed before everything was initiated. + } + super.dispose(); } } diff --git a/core/src/zero1hd/rhythmbullet/audio/AudioProcessorFactory.java b/core/src/zero1hd/rhythmbullet/audio/AudioProcessorFactory.java new file mode 100755 index 0000000..810147b --- /dev/null +++ b/core/src/zero1hd/rhythmbullet/audio/AudioProcessorFactory.java @@ -0,0 +1,12 @@ +package zero1hd.rhythmbullet.audio; + +import com.badlogic.gdx.files.FileHandle; + +import zero1hd.rhythmbullet.audio.processor.AudioProcessor; + +public interface AudioProcessorFactory { + /** + * @return a new {@link #zero1hd.rhythmbullet.audio.processor.AudioProcessor()} from the appropriate platform. + */ + public AudioProcessor newMP3AudioProcessor(FileHandle fileHandle); +} diff --git a/core/src/zero1hd/rhythmbullet/audio/MinimalAudioHeader.java b/core/src/zero1hd/rhythmbullet/audio/MinimalAudioHeader.java new file mode 100755 index 0000000..48fda47 --- /dev/null +++ b/core/src/zero1hd/rhythmbullet/audio/MinimalAudioHeader.java @@ -0,0 +1,37 @@ +package zero1hd.rhythmbullet.audio; + +import java.io.IOException; + +import org.jaudiotagger.audio.AudioFile; +import org.jaudiotagger.audio.AudioFileIO; +import org.jaudiotagger.audio.AudioHeader; +import org.jaudiotagger.audio.exceptions.CannotReadException; +import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; +import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; +import org.jaudiotagger.tag.TagException; + +import com.badlogic.gdx.files.FileHandle; + +public class MinimalAudioHeader { + private int sampleRate, channelCount; + + public MinimalAudioHeader(FileHandle musicFile) { + try { + AudioFile file = AudioFileIO.read(musicFile.file()); + AudioHeader header = file.getAudioHeader(); + sampleRate = header.getSampleRateAsNumber(); + channelCount = (header.getChannels().equals("Mono") ? 1 : 2); + } catch (CannotReadException | IOException | TagException | ReadOnlyFileException + | InvalidAudioFrameException e) { + e.printStackTrace(); + } + } + + public int getSampleRate() { + return sampleRate; + } + + public int getChannelCount() { + return channelCount; + } +} diff --git a/core/src/zero1hd/rhythmbullet/audio/MusicController.java b/core/src/zero1hd/rhythmbullet/audio/MusicController.java new file mode 100755 index 0000000..0dc885c --- /dev/null +++ b/core/src/zero1hd/rhythmbullet/audio/MusicController.java @@ -0,0 +1,223 @@ +package zero1hd.rhythmbullet.audio; + +import java.util.Observable; +import java.util.Observer; +import java.util.Random; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Preferences; +import com.badlogic.gdx.audio.Music; +import com.badlogic.gdx.audio.Music.OnCompletionListener; +import com.badlogic.gdx.files.FileHandle; + +/** + * Manages current games music playback and does this in tandem with the {@link MusicList} by asking to retrieve files and then feeding it to LibGDX. + * Notifies observers when a new song is loaded. + * The loading model is like taking a disk and loading it into a player. It doesn't necessarily mean it'll play right away, but its ready and the only track that has a stream opened. + * @author yunya + * + */ +public class MusicController extends Observable implements OnCompletionListener, Observer { + public enum States { + Loaded, Playing; + } + + private MusicList musicList; + private MinimalAudioHeader musicHeader; + private Music music; + private int currentPlaybackIndex; + private boolean autoPlay; + private boolean shuffle; + private Random rand; + private Preferences prefs; + + public MusicController(MusicList musicList, Preferences prefs) { + if (prefs == null) throw new NullPointerException("preferences can't be null..."); + if (musicList == null) throw new NullPointerException("music list can't be null..."); + musicList.addObserver(this); + this.prefs = prefs; + this.musicList = musicList; + rand = new Random(); + } + + /** + * This play method automatically sets the volume. + */ + public void play() { + if (music != null) { + Gdx.app.debug("MusicListController", "Playing from MLC."); + music.play(); + music.setVolume(prefs.getFloat("music vol", 1f)); + notifyObservers(States.Playing); + } else { + Gdx.app.debug("MusicListController", "failed to begin playing. Load the music!!!"); + } + } + + /** + * Called to pause current song. Does nothing if no song is playing or loaded. + */ + public void pause() { + if (music != null) { + music.pause(); + } + } + + /** + * Loads music based on the index in the {@link MusicList}. + * @param index of music to play + */ + public void setMusicByIndex(int index) { + this.currentPlaybackIndex = index; + loadMusic(); + } + + /** + * Goes to the next track + */ + public void skip() { + currentPlaybackIndex++; + if (shuffle) { + shuffle(false); + } + loadMusic(); + } + + /** + * Goes to the previous track + */ + public void previous() { + currentPlaybackIndex--; + if (shuffle) { + shuffle(false); + } + loadMusic(); + } + + @Override + public void onCompletion(Music music) { + if (autoPlay) { + if (shuffle) { + shuffle(false); + } else { + currentPlaybackIndex++; + } + loadMusic(); + play(); + } + } + + /** + * Shuffles the controller whether the shuffle boolean is true or false. + * @param load whether this method should also make sure to load the music, dispose of the last one, etc. Normally called unless you plan to manually call it elsewhere. + */ + public void shuffle(boolean load) { + Gdx.app.debug("MusicListController", "shuffled."); + if (musicList.getTotal() == 0) { + currentPlaybackIndex = 0; + } else { + currentPlaybackIndex = rand.nextInt(musicList.getTotal()); + } + if (load) { + loadMusic(); + } + } + + public void setAutoPlay(boolean autoPlay) { + this.autoPlay = autoPlay; + } + + public void setShuffle(boolean shuffle) { + this.shuffle = shuffle; + } + + public boolean isShuffle() { + return shuffle; + } + + public boolean isAutoPlay() { + return autoPlay; + } + + /** + * Loads the current selected song. + */ + public void loadMusic() { + Gdx.app.debug("MusicListController", "music is being loaded and listeners are being notified."); + musicHeader = null; + if (music != null) { + music.dispose(); + } + if (currentPlaybackIndex < 0) { + currentPlaybackIndex = musicList.getTotal()-1; + } + if (currentPlaybackIndex >= musicList.getTotal()) { + currentPlaybackIndex = 0; + } + this.music = Gdx.audio.newMusic(musicList.getMusicArray().get(currentPlaybackIndex)); + music.setOnCompletionListener(this); + + setChanged(); + + if (autoPlay) { + play(); + } + notifyObservers(States.Loaded); + } + + public MusicList getMusicList() { + return musicList; + } + + public FileHandle getCurrentMusicFileHandle() { + return musicList.getSongFileHandleFromIndex(currentPlaybackIndex); + } + + public MinimalAudioHeader getCurrentMusicHeader() { + if (musicHeader != null) { + return musicHeader; + } else { + return musicList.newMinimalAudioHeader(getCurrentMusicFileHandle()); + } + } + + @Override + public void update(Observable o, Object arg) { + if (o == musicList) { + loadMusic(); + if (autoPlay) { + play(); + } + } + } + + public String getCurrentSongName() { + return getCurrentMusicFileHandle().nameWithoutExtension(); + } + + public float getCurrentPosition() { + if (music != null) { + return music.getPosition(); + } + return 0; + } + + public void setMusicPosition(float position) { + if (music != null) { + music.setPosition(position); + } + } + + public boolean isPlaying() { + return music.isPlaying(); + } + + /** + * Returns the current music. In no circumstances should this be used to begin playing or it would be playing independent of the controller. + * Doing otherwise would mean you are playing the music separately of the controller. + * @return + */ + public Music getCurrentMusic() { + return music; + } +} diff --git a/core/src/zero1hd/rhythmbullet/audio/MusicList.java b/core/src/zero1hd/rhythmbullet/audio/MusicList.java new file mode 100755 index 0000000..60c6f09 --- /dev/null +++ b/core/src/zero1hd/rhythmbullet/audio/MusicList.java @@ -0,0 +1,135 @@ +package zero1hd.rhythmbullet.audio; + +import java.util.Observable; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Array; + +import zero1hd.rhythmbullet.audio.processor.AudioProcessor; +import zero1hd.rhythmbullet.audio.processor.WAVAudioProcessor; + +/** + * A music list made to store paths to all the songs within a given directory. Can activate the music calling {@link #newAudioProcessor(FileHandle)} and its derivatives. + * Is observable, meaning, given there are observers, will notify when the list completes a refresh. + * @author yunya + */ +public class MusicList extends Observable { + private Array musicList; + private RecursiveMusicSearchThread searchThread; + private AudioProcessorFactory audioProcFactory; + private boolean searched; + + public MusicList(AudioProcessorFactory audioProcessorFactory) { + this.audioProcFactory = audioProcessorFactory; + musicList = new Array<>(); + searchThread = new RecursiveMusicSearchThread("Music Search Thread"); + } + + /** + * Wrapper method that uses async refresh. + * Also notifies listeners that are on the main thread. + */ + public void asyncSearch() { + searchThread.start(); + } + + public void setSearchPath(String searchPath) { + searchThread.setSearchDirectory(Gdx.files.absolute(searchPath)); + setChanged(); + } + + /** + * @param file + * @return a {@link #zero1hd.rhythmbullet.audio.processor.AudioProcessor()} of the given music file. Will return null if theres a format error. + */ + public AudioProcessor newAudioProcessor(FileHandle file) { + if (file.extension().equalsIgnoreCase("wav")) { + return new WAVAudioProcessor(file); + } else if (file.extension().equalsIgnoreCase("mp3")) { + return audioProcFactory.newMP3AudioProcessor(file); + } + return null; + } + + /** + * + * @param file the music file that you need the header for. + * @return the header containing minimal info of the song. + */ + public MinimalAudioHeader newMinimalAudioHeader(FileHandle file) { + return new MinimalAudioHeader(file); + } + + public AudioProcessor newAudioProcessorFromIndex(int index) { + if (!searched) Gdx.app.debug("SongList", "Warning, this list hasn't even searched yet..."); + return newAudioProcessor(musicList.get(index)); + } + + + public FileHandle getSongFileHandleFromIndex(int index) { + if (!searched) Gdx.app.debug("SongList", "Warning, this list hasn't even searched yet..."); + return musicList.get(index); + } + + public Array getMusicArray() { + return musicList; + } + + public boolean isSearched() { + return searched; + } + + private void searchComplete() { + notifyObservers(); + searched = true; + } + + public int getTotal() { + return musicList.size; + } + + private class RecursiveMusicSearchThread implements Runnable { + private Thread thread; + private String threadName; + private FileHandle directory; + + public RecursiveMusicSearchThread(String name) { + this.threadName = name; + } + + public void setSearchDirectory(FileHandle directory) { + this.directory = directory; + } + + @Override + public void run() { + musicList = recursiveMusicSearch(directory); + searchComplete(); + } + + public void start() { + if (thread == null && !thread.isAlive()) { + thread = new Thread(this, threadName); + thread.start(); + } else { + throw new IllegalStateException("Two " + threadName + " instances (threads) were created. This is not allowed for optimization as there is no reason to have two running."); + } + } + + private Array recursiveMusicSearch(FileHandle fileHandle) { + Array musicFiles = new Array<>(); + FileHandle[] files = fileHandle.list(); + for (int i = 0; i < files.length; i++) { + if (files[i].isDirectory()) { + musicFiles.addAll(recursiveMusicSearch(files[i])); + } else { + if (files[i].extension().equalsIgnoreCase("wav") || files[i].extension().equalsIgnoreCase("mp3")) { + musicFiles.add(files[i]); + } + } + } + return musicFiles; + } + } +} diff --git a/core/src/zero1hd/rhythmbullet/audio/MusicMetadataController.java b/core/src/zero1hd/rhythmbullet/audio/MusicMetadataController.java new file mode 100755 index 0000000..42b64d0 --- /dev/null +++ b/core/src/zero1hd/rhythmbullet/audio/MusicMetadataController.java @@ -0,0 +1,102 @@ +package zero1hd.rhythmbullet.audio; + +import java.util.Observable; +import java.util.Observer; + +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Disposable; + +import zero1hd.rhythmbullet.audio.metadata.AudioMetadata; +import zero1hd.rhythmbullet.audio.metadata.MP3Metadata; +import zero1hd.rhythmbullet.audio.metadata.WAVMetadata; + +public class MusicMetadataController implements Disposable, Observer { + private MusicList musicList; + private Array metadataArray; + private MetadataLoadingThread loadingThread; + private volatile boolean searching; + + public MusicMetadataController(MusicList musicList) { + this.musicList = musicList; + metadataArray = new Array<>(); + } + + public MusicList getMusicList() { + return musicList; + } + + /** + * Non-blocking, loads on separate thread. + */ + public void loadSongInfo() { + loadingThread.start(); + } + + public boolean isDone() { + return (metadataArray.size == musicList.getMusicArray().size); + } + + @Override + public void dispose() { + for (int i = 0; i < metadataArray.size; i++) { + metadataArray.get(i).dispose(); + } + } + + public int size() { + return metadataArray.size; + } + + public AudioMetadata getMetadata(int index) { + synchronized (loadingThread) { + return metadataArray.get(index); + } + } + + + public AudioMetadata getInfo(FileHandle filehandle) { + return metadataArray.get(musicList.getMusicArray().indexOf(filehandle, true)); + } + + public boolean isSearching() { + return searching; + } + + private class MetadataLoadingThread implements Runnable { + private Thread thread; + private String name = "Metadata-Load"; + + @Override + public void run() { + searching = true; + for (int i = 0; i < metadataArray.size; i++) { + metadataArray.get(i).dispose(); + } + metadataArray.clear(); + for (int i = 0; i < musicList.getTotal(); i++) { + FileHandle musicFile = musicList.getMusicArray().get(i); + synchronized (this) { + if (musicFile.extension().equalsIgnoreCase("wav")) { + metadataArray.add(new WAVMetadata(musicFile)); + } else if (musicFile.extension().equalsIgnoreCase("mp3")) { + metadataArray.add(new MP3Metadata(musicFile)); + } + } + } + searching = false; + } + + public void start() { + if (thread != null && !thread.isAlive()) { + thread = new Thread(this, name); + thread.start(); + } + } + } + + @Override + public void update(Observable o, Object arg) { + // TODO Auto-generated method stub + } +} diff --git a/core/src/zero1hd/rhythmbullet/audio/RhythmBulletMetadata.java b/core/src/zero1hd/rhythmbullet/audio/RhythmBulletMetadata.java deleted file mode 100755 index b486b19..0000000 --- a/core/src/zero1hd/rhythmbullet/audio/RhythmBulletMetadata.java +++ /dev/null @@ -1,29 +0,0 @@ -package zero1hd.rhythmbullet.audio; - -public class RhythmBulletMetadata { - private String highScore = "0", lastPlayed = "N/A", difficulty = "N/A"; - - public void setHighScore(String highScore) { - this.highScore = highScore; - } - - public void setLastPlayed(String lastPlayed) { - this.lastPlayed = lastPlayed; - } - - public void setDifficulty(String difficulty) { - this.difficulty = difficulty; - } - - public String getHighScore() { - return highScore; - } - - public String getDifficulty() { - return difficulty; - } - - public String getLastPlayed() { - return lastPlayed; - } -} diff --git a/core/src/zero1hd/rhythmbullet/audio/AudioMetadata.java b/core/src/zero1hd/rhythmbullet/audio/metadata/AudioMetadata.java similarity index 90% rename from core/src/zero1hd/rhythmbullet/audio/AudioMetadata.java rename to core/src/zero1hd/rhythmbullet/audio/metadata/AudioMetadata.java index 75eb459..7eefc8b 100755 --- a/core/src/zero1hd/rhythmbullet/audio/AudioMetadata.java +++ b/core/src/zero1hd/rhythmbullet/audio/metadata/AudioMetadata.java @@ -4,7 +4,7 @@ * */ -package zero1hd.rhythmbullet.audio; +package zero1hd.rhythmbullet.audio.metadata; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.Texture; diff --git a/core/src/zero1hd/rhythmbullet/audio/MP3Metadata.java b/core/src/zero1hd/rhythmbullet/audio/metadata/MP3Metadata.java similarity index 94% rename from core/src/zero1hd/rhythmbullet/audio/MP3Metadata.java rename to core/src/zero1hd/rhythmbullet/audio/metadata/MP3Metadata.java index 7698446..9e0050a 100755 --- a/core/src/zero1hd/rhythmbullet/audio/MP3Metadata.java +++ b/core/src/zero1hd/rhythmbullet/audio/metadata/MP3Metadata.java @@ -1,4 +1,4 @@ -package zero1hd.rhythmbullet.audio; +package zero1hd.rhythmbullet.audio.metadata; import java.io.IOException; diff --git a/core/src/zero1hd/rhythmbullet/audio/WAVMetadata.java b/core/src/zero1hd/rhythmbullet/audio/metadata/WAVMetadata.java similarity index 94% rename from core/src/zero1hd/rhythmbullet/audio/WAVMetadata.java rename to core/src/zero1hd/rhythmbullet/audio/metadata/WAVMetadata.java index 7bc3af4..bcaa07b 100755 --- a/core/src/zero1hd/rhythmbullet/audio/WAVMetadata.java +++ b/core/src/zero1hd/rhythmbullet/audio/metadata/WAVMetadata.java @@ -1,4 +1,4 @@ -package zero1hd.rhythmbullet.audio; +package zero1hd.rhythmbullet.audio.metadata; import java.io.IOException; diff --git a/core/src/zero1hd/rhythmbullet/audio/processor/WAVAudioProcessor.java b/core/src/zero1hd/rhythmbullet/audio/processor/WAVAudioProcessor.java index 73a609e..7eb72a8 100755 --- a/core/src/zero1hd/rhythmbullet/audio/processor/WAVAudioProcessor.java +++ b/core/src/zero1hd/rhythmbullet/audio/processor/WAVAudioProcessor.java @@ -7,6 +7,7 @@ import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.UnsupportedAudioFileException; +import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; public class WAVAudioProcessor implements AudioProcessor { @@ -17,11 +18,18 @@ public class WAVAudioProcessor implements AudioProcessor { private AudioInputStream audioInputStream; private boolean initiated; - public WAVAudioProcessor(FileHandle fileHandle, int windowSize) throws IOException, UnsupportedAudioFileException { + public WAVAudioProcessor(FileHandle fileHandle) { this.fileHandle = fileHandle; - AudioFormat format = AudioSystem.getAudioFileFormat(fileHandle.file()).getFormat(); - stereo = format.getChannels() > 1 ? true : false; - sampleRate = (int) format.getSampleRate(); + AudioFormat format; + try { + format = AudioSystem.getAudioFileFormat(fileHandle.file()).getFormat(); + stereo = format.getChannels() > 1 ? true : false; + sampleRate = (int) format.getSampleRate(); + } catch (UnsupportedAudioFileException | IOException e) { + Gdx.app.debug("WAVAudioProcessor", "Couldn't instantiate WAVAUdioProcessor due to error."); + e.printStackTrace(); + } + } @Override diff --git a/core/src/zero1hd/rhythmbullet/audio/visualizer/HorizontalVisualizer.java b/core/src/zero1hd/rhythmbullet/audio/visualizer/HorizontalVisualizer.java index 964dfa4..f01b3be 100755 --- a/core/src/zero1hd/rhythmbullet/audio/visualizer/HorizontalVisualizer.java +++ b/core/src/zero1hd/rhythmbullet/audio/visualizer/HorizontalVisualizer.java @@ -12,7 +12,6 @@ import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Disposable; -import zero1hd.rhythmbullet.audio.MusicManager; public class HorizontalVisualizer implements Disposable { private Pixmap pixmap; diff --git a/core/src/zero1hd/rhythmbullet/util/AdvancedResizeScreen.java b/core/src/zero1hd/rhythmbullet/util/ResizeReadyScreen.java similarity index 81% rename from core/src/zero1hd/rhythmbullet/util/AdvancedResizeScreen.java rename to core/src/zero1hd/rhythmbullet/util/ResizeReadyScreen.java index 51a2fd9..6d7c32d 100755 --- a/core/src/zero1hd/rhythmbullet/util/AdvancedResizeScreen.java +++ b/core/src/zero1hd/rhythmbullet/util/ResizeReadyScreen.java @@ -1,6 +1,6 @@ package zero1hd.rhythmbullet.util; -public interface AdvancedResizeScreen { +public interface ResizeReadyScreen { /** * called before assets are cleared from memory. */ diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/DesktopAssetPack.java b/desktop/src/zero1hd/rhythmbullet/desktop/DesktopAssetPack.java new file mode 100755 index 0000000..ac579ad --- /dev/null +++ b/desktop/src/zero1hd/rhythmbullet/desktop/DesktopAssetPack.java @@ -0,0 +1,224 @@ +package zero1hd.rhythmbullet.desktop; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.assets.AssetManager; +import com.badlogic.gdx.audio.Sound; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.ParticleEffect; +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.Skin; +import com.badlogic.gdx.scenes.scene2d.ui.CheckBox.CheckBoxStyle; +import com.badlogic.gdx.scenes.scene2d.ui.ImageButton.ImageButtonStyle; +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.ScrollPane.ScrollPaneStyle; +import com.badlogic.gdx.scenes.scene2d.ui.SelectBox.SelectBoxStyle; +import com.badlogic.gdx.scenes.scene2d.ui.Slider.SliderStyle; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle; +import com.badlogic.gdx.scenes.scene2d.ui.TextField.TextFieldStyle; +import com.badlogic.gdx.scenes.scene2d.ui.Window.WindowStyle; + +import zero1hd.rhythmbullet.AssetPack; + +public class DesktopAssetPack implements AssetPack { + private FreeTypeFontGenerator default_fontGenerator; + private FreeTypeFontGenerator darktech_ldr_fontGenerator; + + @Override + public void initiateResources() { + default_fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/Gasalt-Regular.ttf")); + darktech_ldr_fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/darktech_ldr.ttf")); + } + + @Override + public void queueTextures(AssetManager assetManager) { + assetManager.load("uiskin.atlas", TextureAtlas.class); + assetManager.load("Tech-Circle1.png", Texture.class); + assetManager.load("polyjet-standard.png", Texture.class); + assetManager.load("keyboard.atlas", TextureAtlas.class); + assetManager.load("cybercircle3B.png", Texture.class); + assetManager.load("title.png", Texture.class); + assetManager.load("cybercircle1.png", Texture.class); + assetManager.load("defaultCover.png", Texture.class); + assetManager.load("laser.png", Texture.class); + assetManager.load("pellet.png", Texture.class); + assetManager.load("shard.png", Texture.class); + assetManager.load("bar.png", Texture.class); + assetManager.load("flake.png", Texture.class); + assetManager.load("void_circle.png", Texture.class); + assetManager.load("tpSelector.png", Texture.class); + assetManager.load("backgrounds/mainBG.png", Texture.class); + assetManager.load("magic1.png", Texture.class); + } + + @Override + public void queueSFX(AssetManager assetManager) { + assetManager.load("pop_open.ogg", Sound.class); + assetManager.load("pop_close.ogg", Sound.class); + assetManager.load("laser.ogg", Sound.class); + assetManager.load("explosion.ogg", Sound.class); + assetManager.load("disintegrate.ogg", Sound.class); + } + + @Override + public void queueParticles(AssetManager assetManager) { + assetManager.load("standard_thrust.p", ParticleEffect.class); + assetManager.load("teleport-cloak.p", ParticleEffect.class); + assetManager.load("explosion-s.p", ParticleEffect.class); + assetManager.load("beateffect.p", ParticleEffect.class); + } + + @Override + public void setupSkin(Skin skin) { + skin.add("default", Color.WHITE); + skin.add("inverse", Color.BLACK); + + TextButtonStyle defaultTextButton = new TextButtonStyle(); + defaultTextButton.up = skin.getDrawable("rect"); + defaultTextButton.down = skin.getDrawable("rect-down"); + defaultTextButton.font = skin.getFont("default-font"); + defaultTextButton.fontColor = skin.getColor("default"); + defaultTextButton.disabled = skin.getDrawable("rect-disabled"); + skin.add("default", defaultTextButton); + + TextButtonStyle subTextbutton = new TextButtonStyle(defaultTextButton); + subTextbutton.font = skin.getFont("sub-font"); + skin.add("sub", subTextbutton); + + TextButtonStyle windowTextButton = new TextButtonStyle(defaultTextButton); + windowTextButton.font = skin.getFont("window-font"); + skin.add("window", windowTextButton); + + TextButtonStyle textButtonLeft = new TextButtonStyle(); + textButtonLeft.up = skin.getDrawable("left-button"); + textButtonLeft.down = skin.getDrawable("left-button-down"); + textButtonLeft.font = skin.getFont("default-font"); + textButtonLeft.fontColor = skin.getColor("default"); + skin.add("left", textButtonLeft); + + SliderStyle defaultSlider = new SliderStyle(skin.getDrawable("default-slider"), skin.getDrawable("default-slider-knob")); + skin.add("default-horizontal", defaultSlider); + + SliderStyle vertSlider = new SliderStyle(defaultSlider); + vertSlider.knob = skin.getDrawable("vertical-slider-knob"); + skin.add("default-vertical", vertSlider); + + LabelStyle defaultLabel = new LabelStyle(); + defaultLabel.font = skin.getFont("default-font"); + defaultLabel.fontColor = skin.getColor("default"); + skin.add("default", defaultLabel); + + TextFieldStyle defaultTextField = new TextFieldStyle(skin.getFont("sub-font"), skin.getColor("default"), skin.getDrawable("cursor"), skin.getDrawable("selection"), skin.getDrawable("textfield")); + skin.add("default", defaultTextField); + + TextFieldStyle uiTextField = new TextFieldStyle(defaultTextField); + uiTextField.font = skin.getFont("window-font"); + skin.add("ui", uiTextField); + + WindowStyle defaultWindow = new WindowStyle(skin.getFont("window-font"), skin.getColor("default"), skin.getDrawable("default-window")); + skin.add("default", defaultWindow); + + WindowStyle tintedWindow = new WindowStyle(defaultWindow); + tintedWindow.titleFontColor = skin.getColor("inverse"); + tintedWindow.background = skin.getDrawable("tinted-window"); + skin.add("tinted", tintedWindow); + + ListStyle defaultList = new ListStyle(skin.getFont("window-font"), skin.getColor("inverse"), skin.getColor("default"), skin.getDrawable("selection")); + skin.add("default", defaultList); + + ScrollPaneStyle defaultScrollPane = new ScrollPaneStyle(); + defaultScrollPane.vScroll = skin.getDrawable("default-scroll"); + defaultScrollPane.hScrollKnob = skin.getDrawable("default-round-large"); + defaultScrollPane.hScroll = skin.getDrawable("default-scroll"); + defaultScrollPane.vScrollKnob = skin.getDrawable("default-round-large"); + skin.add("default", defaultScrollPane); + + CheckBoxStyle defaultCheckBox = new CheckBoxStyle(skin.getDrawable("check-off"), skin.getDrawable("check-on"), skin.getFont("window-font"), skin.getColor("default")); + defaultCheckBox.checkboxOffDisabled = skin.getDrawable("check-disabled"); + skin.add("default", defaultCheckBox); + + SelectBoxStyle defaultSelectBox = new SelectBoxStyle(skin.getFont("default-font"), skin.getColor("default"), skin.getDrawable("default-select"), defaultScrollPane, defaultList); + skin.add("default", defaultSelectBox); + + Gdx.app.debug("Prelaunch Debug Info", "UI Skin has been defined."); + + CheckBoxStyle playButtonStyle = new CheckBoxStyle(defaultCheckBox); + playButtonStyle.checkboxOn = skin.getDrawable("play-down"); + playButtonStyle.checkboxOff = skin.getDrawable("play"); + skin.add("play-button", playButtonStyle); + + ImageButtonStyle pauseButtonStyle = new ImageButtonStyle(); + pauseButtonStyle.down = skin.getDrawable("pause-down"); + pauseButtonStyle.up = skin.getDrawable("pause"); + skin.add("pause-button", pauseButtonStyle); + + ImageButtonStyle fastForwardButtonStyle = new ImageButtonStyle(); + fastForwardButtonStyle.down = skin.getDrawable("fast-forward-down"); + fastForwardButtonStyle.up = skin.getDrawable("fast-forward"); + skin.add("fast-forward-button", fastForwardButtonStyle); + + ImageButtonStyle reverseButtonStyle = new ImageButtonStyle(); + reverseButtonStyle.down = skin.getDrawable("rewind-down"); + reverseButtonStyle.up = skin.getDrawable("rewind"); + skin.add("rewind-button", reverseButtonStyle); + + CheckBoxStyle shuffleButtonStyle = new CheckBoxStyle(defaultCheckBox); + shuffleButtonStyle.checkboxOff = skin.getDrawable("shuffle"); + shuffleButtonStyle.checkboxOn = skin.getDrawable("shuffle-down"); + skin.add("shuffle-button", shuffleButtonStyle); + } + + @Override + public void generateFonts(Skin skin) { + int height = Gdx.graphics.getHeight(); + + skin.add("window-font", default_fontGenerator.generateFont(new FreeTypeFontParameter() { + { + size = 18; + } + })); + skin.add("sub-font", default_fontGenerator.generateFont(new FreeTypeFontParameter() { + { + size = fontScale(0.05f, height); + } + })); + skin.add("default-font", default_fontGenerator.generateFont(new FreeTypeFontParameter() { + { + size = fontScale(0.07f, height); + } + })); + skin.add("large-font", default_fontGenerator.generateFont(new FreeTypeFontParameter() { + { + size = fontScale(0.085f, height); + } + })); + skin.add("special-font", darktech_ldr_fontGenerator.generateFont(new FreeTypeFontParameter() { + { + size = fontScale(0.075f, height); + } + })); + } + + public int fontScale(float fontSize, int height) { + int size = MathUtils.round(Gdx.graphics.getDensity()*(fontSize*height)); + if (size >= 200) { + size = 200; + } + return size; + } + + @Override + public void complete(AssetManager assetManager) { + assetManager.get("standard_thrust.p", ParticleEffect.class).flipY(); + } + + @Override + public void dispose() { + darktech_ldr_fontGenerator.dispose(); + default_fontGenerator.dispose(); + } +} diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/DesktopLauncher.java b/desktop/src/zero1hd/rhythmbullet/desktop/DesktopLauncher.java index bfa2d84..17924a6 100755 --- a/desktop/src/zero1hd/rhythmbullet/desktop/DesktopLauncher.java +++ b/desktop/src/zero1hd/rhythmbullet/desktop/DesktopLauncher.java @@ -1,8 +1,5 @@ package zero1hd.rhythmbullet.desktop; -import java.util.logging.Level; -import java.util.logging.Logger; - import com.badlogic.gdx.backends.lwjgl.LwjglApplication; import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; @@ -11,16 +8,15 @@ import zero1hd.rhythmbullet.desktop.screens.SplashScreen; public class DesktopLauncher { public static void main (String[] arg) { - Logger.getLogger("org.jaudiotagger").setLevel(Level.OFF); - RhythmBullet core; LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); config.title = "Rhythm Bullet"; config.resizable = false; config.allowSoftwareMode = true; config.useHDPI = true; + core = new RhythmBullet(); - core.setInitialScreen(new SplashScreen(core)); + core.setup(new SplashScreen(), new DesktopAssetPack()); new LwjglApplication(core, config); diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/audio/MusicInfoController.java b/desktop/src/zero1hd/rhythmbullet/desktop/audio/MusicInfoController.java deleted file mode 100755 index 823c63e..0000000 --- a/desktop/src/zero1hd/rhythmbullet/desktop/audio/MusicInfoController.java +++ /dev/null @@ -1,64 +0,0 @@ -package zero1hd.rhythmbullet.desktop.audio; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.Preferences; -import com.badlogic.gdx.files.FileHandle; -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.Disposable; - -import zero1hd.rhythmbullet.audio.MusicInfo; - -public class MusicInfoController implements Disposable { - private MusicList musicList; - private ExecutorService exec; - private Array songInfoArray; - private Preferences musicAnnotation; - - public MusicInfoController(MusicList musicList) { - this.musicList = musicList; - songInfoArray = new Array<>(); - exec = Executors.newSingleThreadExecutor(); - musicAnnotation = Gdx.app.getPreferences("MusicAnnotation"); - } - - public MusicList getMusicList() { - return musicList; - } - - /** - * Non-blocking, loads on separate thread. - */ - public void loadSongInfo() { - for (int i = 0; i < songInfoArray.size; i++) { - songInfoArray.get(i).dispose(); - } - songInfoArray.clear(); - exec.submit(() -> { - for (int i = 0; i < musicList.getTotal(); i++) { - MusicInfo musicInfo = new MusicInfo(musicList.getMusicArray().get(i), musicAnnotation); - musicInfo.loadInfo(); - songInfoArray.add(musicInfo); - } - }); - } - - public boolean isDone() { - return (songInfoArray.size == musicList.getMusicArray().size); - } - - @Override - public void dispose() { - exec.shutdown(); - } - - public Array getSongInfoArray() { - return songInfoArray; - } - - public MusicInfo getInfo(FileHandle filehandle) { - return songInfoArray.get(musicList.getMusicArray().indexOf(filehandle, true)); - } -} diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/audio/MusicList.java b/desktop/src/zero1hd/rhythmbullet/desktop/audio/MusicList.java deleted file mode 100755 index e6130d9..0000000 --- a/desktop/src/zero1hd/rhythmbullet/desktop/audio/MusicList.java +++ /dev/null @@ -1,129 +0,0 @@ -package zero1hd.rhythmbullet.desktop.audio; - -import java.util.Comparator; -import java.util.Observable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.files.FileHandle; -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.Sort; - -import zero1hd.rhythmbullet.audio.MusicManager; -import zero1hd.rhythmbullet.desktop.audio.processor.MP3AudioProcessor; - -public class MusicList extends Observable { - private Array musicArray; - private String searchPath; - private boolean searched; - private ExecutorService exec; - - public MusicList() { - musicArray = new Array<>(); - exec = Executors.newSingleThreadExecutor(); - } - - private Array recursiveMusicFileList(FileHandle fileHandle) { - Array musicFiles = new Array<>(); - FileHandle[] files = fileHandle.list(); - for (int i = 0; i < files.length; i++) { - if (files[i].isDirectory()) { - musicFiles.addAll(recursiveMusicFileList(files[i])); - } else { - if (files[i].extension().equalsIgnoreCase("wav") || files[i].extension().equalsIgnoreCase("mp3")) { - musicFiles.add(files[i]); - } - } - } - return musicFiles; - } - - /** - * refreshes song list, notifies any observers of the refresh while passing no argument to the notifier. - * Blocking. - */ - public void refresh(boolean notifyOnCompletion) { - searched = false; - musicArray.clear(); - Gdx.app.debug("SongController", "Searching path: " + searchPath); - if (Gdx.files.absolute(searchPath).exists() && Gdx.files.absolute(searchPath).isDirectory()) { - musicArray.addAll(recursiveMusicFileList(Gdx.files.absolute(searchPath))); - } - if (!Gdx.files.external("RhythmBullet/Alan Walker - Spectre.mp3").exists()) { - Gdx.files.internal("music/Alan Walker - Spectre.mp3").copyTo(Gdx.files.external("RhythmBullet/Alan Walker - Spectre.mp3")); - } - musicArray.add(Gdx.files.external("RhythmBullet/Alan Walker - Spectre.mp3")); - setChanged(); - Sort.instance().sort(musicArray, new Comparator() { - @Override - public int compare(FileHandle o1, FileHandle o2) { - return o1.nameWithoutExtension().compareTo(o2.nameWithoutExtension()); - } - }); - - searched = true; - - if (notifyOnCompletion) { - notifyObservers(); - } - } - - /** - * Wrapper method that uses asynch refresh. - * Also notifies listeners that are on the main thread. - */ - public void asynchRefresh() { - searched = false; - exec.submit(() -> { - refresh(false); - Gdx.app.debug("Asynch-MusicList", "Async refresh done. Notification has been sent."); - Gdx.app.postRunnable(() -> { - notifyObservers(); - searched = true; - }); - }); - } - - public void setSearchPath(String searchPath) { - this.searchPath = searchPath; - setChanged(); - } - - /** - * creates an audio manager for the given music file. - * @param file - * @return a music manager of the given music file. - */ - public MusicManager getAudioData(FileHandle file) { - if (file.extension().equalsIgnoreCase("wav")) { - return new WAVManager(file); - } else if (file.extension().equalsIgnoreCase("mp3")) { - return new MP3AudioProcessor(file); - } - return null; - } - - public MusicManager getMusicManagerFromIndex(int index) { - if (!searched) Gdx.app.debug("SongList", "Warning, this list hasn't even searched yet..."); - return getAudioData(musicArray.get(index)); - } - - public int getTotal() { - return musicArray.size; - } - - public FileHandle getSongFileHandleFromIndex(int index) { - if (!searched) Gdx.app.debug("SongList", "Warning, this list hasn't even searched yet..."); - return musicArray.get(index); - } - - public Array getMusicArray() { - return musicArray; - } - - public boolean isSearched() { - return searched; - } - -} diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/audio/MusicListController.java b/desktop/src/zero1hd/rhythmbullet/desktop/audio/MusicListController.java deleted file mode 100755 index bc7e59a..0000000 --- a/desktop/src/zero1hd/rhythmbullet/desktop/audio/MusicListController.java +++ /dev/null @@ -1,154 +0,0 @@ -package zero1hd.rhythmbullet.desktop.audio; - -import java.util.Observable; -import java.util.Observer; -import java.util.Random; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.Preferences; -import com.badlogic.gdx.audio.Music; -import com.badlogic.gdx.audio.Music.OnCompletionListener; - -import zero1hd.rhythmbullet.audio.MusicManager; - -public class MusicListController extends Observable implements OnCompletionListener, Observer { - private MusicList musicList; - private MusicManager mm; - private int currentPlaybackID; - private boolean autoPlay; - private boolean shuffle; - private Random rand; - - private Preferences prefs; - public MusicListController(MusicList musicList, Preferences prefs) { - if (prefs == null) throw new NullPointerException("preferences can't be null..."); - if (musicList == null) throw new NullPointerException("music list can't be null..."); - musicList.addObserver(this); - this.prefs = prefs; - this.musicList = musicList; - rand = new Random(); - } - - /** - * This play method automatically sets the volume. - */ - public void play() { - if (mm != null) { - Gdx.app.debug("MusicListController", "Playing from MLC."); - mm.play(); - mm.setVolume(prefs.getFloat("music vol", 1f)); - } else { - Gdx.app.debug("MusicListController", "failed to begin playing. Load the music!!!"); - } - } - - public void pause() { - if (mm != null) { - mm.pause(); - } - } - - public void setMusicByIndex(int index) { - this.currentPlaybackID = index; - loadMusic(); - } - - public void skip() { - currentPlaybackID++; - if (shuffle) { - shuffle(false); - } - loadMusic(); - } - - public void previous() { - currentPlaybackID--; - if (shuffle) { - shuffle(false); - } - loadMusic(); - } - - @Override - public void onCompletion(Music music) { - if (autoPlay) { - if (shuffle) { - shuffle(false); - } else { - currentPlaybackID++; - } - loadMusic(); - play(); - } - } - - /** - * Shuffles the controller whether the shuffle boolean is true or false. - * @param load whether this method should also make sure to load the music, dispose of the last one, etc. Normally called unless you plan to manually call it elswhere. - */ - public void shuffle(boolean load) { - Gdx.app.debug("MusicListController", "shuffled."); - if (musicList.getTotal() == 0) { - currentPlaybackID = 0; - } else { - currentPlaybackID = rand.nextInt(musicList.getTotal()); - } - if (load) { - loadMusic(); - } - } - - public void setAutoPlay(boolean autoPlay) { - this.autoPlay = autoPlay; - } - - public void setShuffle(boolean shuffle) { - this.shuffle = shuffle; - } - - public boolean isShuffle() { - return shuffle; - } - - public boolean isAutoPlay() { - return autoPlay; - } - - /** - * Loads the current selected song. - */ - public void loadMusic() { - Gdx.app.debug("MusicListController", "music is being loaded and listeners are being notified."); - if (mm != null) { - mm.dispose(); - } - if (currentPlaybackID < 0) { - currentPlaybackID = musicList.getTotal()-1; - } - if (currentPlaybackID >= musicList.getTotal()) { - currentPlaybackID = 0; - } - this.mm = musicList.getMusicManagerFromIndex(currentPlaybackID); - mm.setOnCompletionListener(this); - - setChanged(); - notifyObservers(mm); - } - - public MusicList getMusicList() { - return musicList; - } - - - public MusicManager getCurrentMusicManager() { - return mm; - } - - @Override - public void update(Observable o, Object arg) { - if (o == musicList) { - loadMusic(); - play(); - } - } -} diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/audio/map/RhythmMapAlgorithm.java b/desktop/src/zero1hd/rhythmbullet/desktop/audio/map/RhythmMapAlgorithm.java deleted file mode 100755 index c839b67..0000000 --- a/desktop/src/zero1hd/rhythmbullet/desktop/audio/map/RhythmMapAlgorithm.java +++ /dev/null @@ -1,73 +0,0 @@ -package zero1hd.rhythmbullet.desktop.audio.map; - -import org.apache.commons.math3.random.MersenneTwister; - -import com.badlogic.gdx.utils.FloatArray; - -import zero1hd.rhythmbullet.audio.AudioDataPackage; -import zero1hd.rhythmbullet.entity.EntityManager; -import zero1hd.rhythmbullet.entity.coordinator.CoordinatorManager; -import zero1hd.rhythmbullet.game.EntitySpawnInfo; -import zero1hd.rhythmbullet.game.GamePlayMap; - -public class RhythmMapAlgorithm implements Runnable { - - private EntityManager em; - private CoordinatorManager cm; - - private FloatArray bassPeaks; - private FloatArray mPeaks; - private FloatArray umPeaks; - private MersenneTwister rand; - private GamePlayMap map; - - private float avgBass; - private float avgUM; - private float avgSPB; - private float umMax, bassMax; - - private float speedMod, healthMod, difficultyMod; - - private float windowPerSecond; - - private volatile int progress; - public RhythmMapAlgorithm(EntityManager em, CoordinatorManager cm, AudioDataPackage adp, float speedMod, float healthMod, float difficultyMod) { - this.cm = cm; - this.em = em; - - bassPeaks = adp.getBassPeaks(); - mPeaks = adp.getmPeaks(); - umPeaks = adp.getuMPeaks(); - map = new GamePlayMap(adp.getMusicInfo(), umPeaks.size); - rand = new MersenneTwister(adp.getPUID()); - avgSPB = adp.getAvgSPB(); - windowPerSecond = 1/adp.getSecPerWin(); - - this.speedMod = speedMod; - this.healthMod = healthMod; - this.difficultyMod = difficultyMod; - - umMax = adp.getuMMaxval(); - avgUM = adp.getuMAvg(); - - bassMax = adp.getBassMaxVal(); - avgBass = adp.getBassAvg(); - } - - - EntitySpawnInfo esi; - @Override - public void run() { - map.beginBuild(); - //TODO Map gen algorithm - map.endBuild(); - } - - public synchronized GamePlayMap getMap() { - return map; - } - - public synchronized int getProgress() { - return progress; - } -} diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/audio/processor/DesktopAudioProcessorFactory.java b/desktop/src/zero1hd/rhythmbullet/desktop/audio/processor/DesktopAudioProcessorFactory.java new file mode 100755 index 0000000..efbb106 --- /dev/null +++ b/desktop/src/zero1hd/rhythmbullet/desktop/audio/processor/DesktopAudioProcessorFactory.java @@ -0,0 +1,13 @@ +package zero1hd.rhythmbullet.desktop.audio.processor; + +import com.badlogic.gdx.files.FileHandle; + +import zero1hd.rhythmbullet.audio.AudioProcessorFactory; +import zero1hd.rhythmbullet.audio.processor.AudioProcessor; + +public class DesktopAudioProcessorFactory implements AudioProcessorFactory { + @Override + public AudioProcessor newMP3AudioProcessor(FileHandle fileHandle) { + return new MP3AudioProcessor(fileHandle); + } +} diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/audio/visualizer/DesktopVisualizer.java b/desktop/src/zero1hd/rhythmbullet/desktop/audio/visualizer/DesktopVisualizer.java index 5264ec0..d231fa9 100755 --- a/desktop/src/zero1hd/rhythmbullet/desktop/audio/visualizer/DesktopVisualizer.java +++ b/desktop/src/zero1hd/rhythmbullet/desktop/audio/visualizer/DesktopVisualizer.java @@ -4,56 +4,64 @@ import static org.lwjgl.openal.AL10.alGetSourcef; import java.nio.ByteBuffer; import java.nio.ShortBuffer; +import java.util.Observable; +import java.util.Observer; import org.lwjgl.openal.AL11; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.backends.lwjgl.audio.OpenALMusic; -import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.utils.TimeUtils; import com.badlogic.gdx.utils.reflect.ClassReflection; import com.badlogic.gdx.utils.reflect.Field; import com.badlogic.gdx.utils.reflect.ReflectionException; -import zero1hd.rhythmbullet.audio.visualizer.MusicManagerFFT; -import zero1hd.rhythmbullet.audio.visualizer.Visualizer; +import zero1hd.rhythmbullet.audio.MinimalAudioHeader; +import zero1hd.rhythmbullet.audio.MusicController; -public class DesktopVisualizer extends MusicManagerFFT implements Visualizer { +public class DesktopVisualizer implements Observer { + private int windowSize = 1024; + private float[] PCM = new float[windowSize]; private ShortBuffer playingBuffer; private ShortBuffer compareBuffer; private ShortBuffer buffer; private int sourceID; - + private int channelCount; + private int sampleRate; + private MusicController mc; + private BufferStreamReadThread streamReadThread; + private int windowsRead; + private int currentPlaybackWindow; + public DesktopVisualizer() { - super(); try { Field bufferField = ClassReflection.getDeclaredField(OpenALMusic.class, "tempBuffer"); bufferField.setAccessible(true); + Field bufferSizeField = ClassReflection.getDeclaredField(OpenALMusic.class, "bufferSize"); + bufferSizeField.setAccessible(true); + bufferSizeField.set(null, new Integer(4096*5)); + buffer = ((ByteBuffer) bufferField.get(null)).asShortBuffer().asReadOnlyBuffer(); } catch (IllegalArgumentException | SecurityException | ReflectionException e) { e.printStackTrace(); Gdx.app.debug("Visualizer reflection", "Failed attempt at retrieving tempBuffer field."); Gdx.app.exit(); } + + streamReadThread = new BufferStreamReadThread(); } - /* (non-Javadoc) - * @see zero1hd.rhythmbullet.desktop.audio.visualizer.Visualizer#calcPCMData() - */ - @Override - public void calcPCMData() { + private synchronized void calcPCMData() { short chanVal; - int bufferPosOffset = 0; - bufferPosOffset = updateBufferPosition(); - playingBuffer.position(Math.max(playingBuffer.limit()+bufferPosOffset, 0)); - for (int sid = 0; sid < getAudioPCM().length && sid < playingBuffer.remaining(); sid++) { - getAudioPCM()[sid] = 0; - for (int channel = 0; channel < mm.getChannelCount(); channel ++) { - if (getAudioPCM()[sid] < (chanVal = playingBuffer.get())) { - getAudioPCM()[sid] = chanVal; + for (int sid = 0; sid < PCM.length && sid < playingBuffer.remaining(); sid++) { + PCM[sid] = 0; + for (int channel = 0; channel < channelCount; channel ++) { + if (PCM[sid] < (chanVal = playingBuffer.get())) { + PCM[sid] = chanVal; } } - getAudioPCM()[sid] /= Short.MAX_VALUE+1f; + PCM[sid] /= Short.MAX_VALUE+1f; } @@ -86,27 +94,32 @@ public class DesktopVisualizer extends MusicManagerFFT implements Visualizer { } //put the new buffer into the remaining portion. playingBuffer.put(compareBuffer); + + synchronizeBufferWithPlayback(); } - private int updateBufferPosition() { - int pos = (int) ((alGetSourcef(sourceID, AL11.AL_SAMPLE_OFFSET))-buffer.limit()-mm.getChannelCount()*mm.getReadWindowSize()); - return pos; + private int calcBufferPosition() { + int offset = (int) alGetSourcef(sourceID, AL11.AL_SAMPLE_OFFSET); + offset = (offset/windowSize) * windowSize; + return offset; } - /* (non-Javadoc) - * @see zero1hd.rhythmbullet.desktop.audio.visualizer.Visualizer#setMM(zero1hd.rhythmbullet.audio.MusicManager) - */ - @Override - public void setMM(MusicManager mm) { + private void synchronizeBufferWithPlayback() { + playingBuffer.position(calcBufferPosition()); + windowsRead = (int) ((mc.getCurrentPosition()*sampleRate)/windowSize); + } + + public void setMusic(MinimalAudioHeader header) { try { Field sourceIDField = ClassReflection.getDeclaredField(OpenALMusic.class, "sourceID"); sourceIDField.setAccessible(true); - sourceID = (int) sourceIDField.get(mm.getMusic()); + sourceID = (int) sourceIDField.get(mc.getCurrentMusic()); } catch (ReflectionException e) { e.printStackTrace(); } - int originalPos = buffer.position(); - + channelCount = header.getChannelCount(); + sampleRate = header.getSampleRate(); + playingBuffer = ShortBuffer.allocate(buffer.capacity()*2); buffer.rewind(); playingBuffer.put(buffer); @@ -117,28 +130,76 @@ public class DesktopVisualizer extends MusicManagerFFT implements Visualizer { compareBuffer.put(buffer); compareBuffer.flip(); - buffer.position(originalPos); - this.mm = mm; + buffer.rewind(); + } + + public synchronized float[] getAudioPCM() { + return PCM; + } + + public class BufferStreamReadThread implements Runnable { + private String name = "PCM-Audio-Processing"; + private Thread thread; + private boolean run, paused; + private volatile long timeOfLastRead; + private int waitTime; + + @Override + public void run() { + while (run) { + if (mc.isPlaying()) { + if (paused) { + timeOfLastRead = TimeUtils.millis(); + paused = false; + } + waitTime = sampleRate/windowSize/Gdx.graphics.getFramesPerSecond(); + if (TimeUtils.timeSinceMillis(timeOfLastRead) >= waitTime) { + calcPCMData(); + windowsRead++; + timeOfLastRead = TimeUtils.millis(); + + + currentPlaybackWindow = (int) ((mc.getCurrentPosition()*sampleRate)/windowSize); + if (windowsRead != currentPlaybackWindow) { + synchronizeBufferWithPlayback(); + } + } + } else { + synchronized (this) { + try { + paused = true; + wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + } - super.setMM(mm); + public synchronized void start() { + if (thread == null && !thread.isAlive()) { + thread = new Thread(this, name); + thread.start(); + } else { + notify(); + } + } } - + @Override - public MusicManager getMM() { - return mm; - } - - @Override - public void render(Batch batch, float parentAlpha) { - } - - @Override - public float[] getAudioPCMData() { - return getAudioPCM(); - } - - @Override - public void fft() { - calculate(); + public void update(Observable o, Object arg) { + if (o == mc) { + switch ((MusicController.States) arg) { + case Loaded: + setMusic(mc.getCurrentMusicHeader()); + break; + case Playing: + streamReadThread.start(); + break; + default: + break; + } + } } } diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/components/GraphicsOptions.java b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/components/GraphicsOptions.java index 04938db..f37301e 100755 --- a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/components/GraphicsOptions.java +++ b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/components/GraphicsOptions.java @@ -11,7 +11,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.utils.Align; -import zero1hd.rhythmbullet.desktop.screens.MainMenuScreen; +import zero1hd.rhythmbullet.desktop.screens.MainScreen; public class GraphicsOptions extends Table { private Label resolutions, shaders; @@ -28,7 +28,7 @@ public class GraphicsOptions extends Table { _1366x768; - public GraphicsOptions(final MainMenuScreen mainMenu, Skin skin, final Preferences prefs) { + public GraphicsOptions(final MainScreen mainMenu, Skin skin, final Preferences prefs) { align(Align.center); defaults().space(10f); this.prefs = prefs; diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/components/HorizontalVisualizerWidget.java b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/components/HorizontalVisualizerWidget.java index 18cf596..1dcfc31 100755 --- a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/components/HorizontalVisualizerWidget.java +++ b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/components/HorizontalVisualizerWidget.java @@ -1,19 +1,19 @@ package zero1hd.rhythmbullet.desktop.graphics.ui.components; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.audio.Music; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.scenes.scene2d.ui.Widget; import com.badlogic.gdx.utils.Disposable; -import zero1hd.rhythmbullet.audio.MusicManager; import zero1hd.rhythmbullet.audio.visualizer.HorizontalVisualizer; import zero1hd.rhythmbullet.desktop.audio.visualizer.DesktopVisualizer; public class HorizontalVisualizerWidget extends Widget implements Disposable { private HorizontalVisualizer vis; private boolean updatePositioning = true; - private MusicManager mm; + private Music music; private boolean initialLoad; private float visRefreshRate; private float timer; @@ -29,13 +29,13 @@ public class HorizontalVisualizerWidget extends Widget implements Disposable { @Override public void act(float delta) { - if (mm != null && mm.isFinishedLoading() && !initialLoad) { - visRefreshRate = mm.getReadWindowSize()/mm.getSampleRate(); - Gdx.app.debug("Visualizer", "\nsample count: " + mm.getSampleCount() - + "\nDuration in seconds: " + mm.getDuration() + - "\nSample rate: " + mm.getSampleRate() + + if (music != null && music.isFinishedLoading() && !initialLoad) { + visRefreshRate = music.getReadWindowSize()/music.getSampleRate(); + Gdx.app.debug("Visualizer", "\nsample count: " + music.getSampleCount() + + "\nDuration in seconds: " + music.getDuration() + + "\nSample rate: " + music.getSampleRate() + "\nRefresh rate: " + visRefreshRate); - vis.setMM(mm); + vis.setMusic(music); initialLoad = true; } @@ -46,7 +46,7 @@ public class HorizontalVisualizerWidget extends Widget implements Disposable { vis.update(delta); updateVisualizerProperties(); - if (mm != null && initialLoad) { + if (music != null && initialLoad) { if (timer >= visRefreshRate) { timer = 0; vis.calculate(); @@ -58,9 +58,9 @@ public class HorizontalVisualizerWidget extends Widget implements Disposable { super.act(delta); } - public void setMM(MusicManager mm) { + public void setMusic(Music music) { initialLoad = false; - this.mm = mm; + this.music = music; } @Override diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/components/MusicControls.java b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/components/MusicControls.java index 21084d6..9b2365f 100755 --- a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/components/MusicControls.java +++ b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/components/MusicControls.java @@ -7,13 +7,13 @@ import com.badlogic.gdx.scenes.scene2d.ui.ImageButton; import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; -import zero1hd.rhythmbullet.desktop.audio.MusicListController; +import zero1hd.rhythmbullet.audio.MusicController; public class MusicControls extends HorizontalGroup { private ImageButton reverse, forward; private CheckBox shuffle, play; private float disableTimer; - public MusicControls(Skin skin, final MusicListController sc) { + public MusicControls(Skin skin, final MusicController sc) { reverse = new ImageButton(skin, "rewind-button"); reverse.addListener(new ChangeListener() { @Override diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/AnalysisPage.java b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/AnalysisPage.java index 2906a23..4d89801 100755 --- a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/AnalysisPage.java +++ b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/AnalysisPage.java @@ -39,7 +39,7 @@ public class AnalysisPage extends Page { addActor(table); this.core = core; adjustment = new Table(); - Skin skin = core.getDefaultSkin(); + Skin skin = core.getSkinSkin(); difficultyModLabel = new Label("Difficulty Modifier: ", skin, "sub-font", skin.getColor("default")); difficultyModifierSlider = new Slider(1, 3, 0.5f, false, skin); diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/GraphicsOptionsPage.java b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/GraphicsOptionsPage.java index 9d35bd4..35a435e 100755 --- a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/GraphicsOptionsPage.java +++ b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/GraphicsOptionsPage.java @@ -10,14 +10,14 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import zero1hd.rhythmbullet.desktop.graphics.ui.components.GraphicsOptions; -import zero1hd.rhythmbullet.desktop.screens.MainMenuScreen; +import zero1hd.rhythmbullet.desktop.screens.MainScreen; public class GraphicsOptionsPage extends Page { private ScrollPane scrollPane; private GraphicsOptions graphicsTable; private TextButton backButton; - public GraphicsOptionsPage(Skin skin, Preferences prefs, final MainMenuScreen menu, AssetManager assets) { + public GraphicsOptionsPage(Skin skin, Preferences prefs, final MainScreen menu, AssetManager assets) { graphicsTable = new GraphicsOptions(menu, skin, prefs); scrollPane = new ScrollPane(graphicsTable, skin); scrollPane.setFadeScrollBars(false); diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/MainPage.java b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/MainPage.java index 3ab2cb0..003eebc 100755 --- a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/MainPage.java +++ b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/MainPage.java @@ -14,17 +14,16 @@ import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.utils.Align; import zero1hd.rhythmbullet.RhythmBullet; -import zero1hd.rhythmbullet.audio.MusicManager; -import zero1hd.rhythmbullet.desktop.audio.MusicListController; +import zero1hd.rhythmbullet.audio.MusicController; import zero1hd.rhythmbullet.desktop.graphics.ui.components.MusicControls; import zero1hd.rhythmbullet.desktop.graphics.ui.components.TitleBarVisualizer; -import zero1hd.rhythmbullet.desktop.screens.MainMenuScreen; +import zero1hd.rhythmbullet.desktop.screens.MainScreen; import zero1hd.rhythmbullet.graphics.ui.components.ScrollText; public class MainPage extends Page implements Observer { private Label versionLabel; - private MusicListController mlc; + private MusicController mc; private TitleBarVisualizer titleBar; private Table table; private TextButton playButton; @@ -32,17 +31,17 @@ public class MainPage extends Page implements Observer { private TextButton quitButton; private MusicControls musicControls; - private MainMenuScreen mMenu; + private MainScreen mMenu; private ScrollText scrollText; - public MainPage(RhythmBullet core, final Vector3 targetPosition, MusicListController mlc, final MainMenuScreen mainMenu) { - this.mlc = mlc; + public MainPage(RhythmBullet core, Vector3 targetPosition, MusicController mlc, MainScreen mainMenu) { + this.mc = mlc; this.mMenu = mainMenu; titleBar = new TitleBarVisualizer(core.getAssetManager()); addActor(titleBar); - versionLabel = new Label("Version: " + RhythmBullet.VERSION, core.getDefaultSkin(), "sub-font", - core.getDefaultSkin().getColor("default")); + versionLabel = new Label("Version: " + RhythmBullet.VERSION, core.getSkinSkin(), "sub-font", + core.getSkinSkin().getColor("default")); versionLabel.setPosition(3, 3); addActor(versionLabel); @@ -51,7 +50,7 @@ public class MainPage extends Page implements Observer { table.align(Align.center); table.defaults().space(10f); addActor(table); - playButton = new TextButton("Start!", core.getDefaultSkin()); + playButton = new TextButton("Start!", core.getSkinSkin()); playButton.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -63,7 +62,7 @@ public class MainPage extends Page implements Observer { table.row(); - optionsButton = new TextButton("Options", core.getDefaultSkin(), "sub"); + optionsButton = new TextButton("Options", core.getSkinSkin(), "sub"); optionsButton.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -74,7 +73,7 @@ public class MainPage extends Page implements Observer { table.row(); - quitButton = new TextButton("Quit", core.getDefaultSkin(), "sub"); + quitButton = new TextButton("Quit", core.getSkinSkin(), "sub"); quitButton.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -83,11 +82,11 @@ public class MainPage extends Page implements Observer { }); table.add(quitButton).fillX(); - musicControls = new MusicControls(core.getDefaultSkin(), mlc); + musicControls = new MusicControls(core.getSkinSkin(), mlc); musicControls.setPosition((getWidth()-musicControls.getMinWidth() - 20f), getHeight()-musicControls.getMinHeight()-20f); addActor(musicControls); - scrollText = new ScrollText("...", "...", core.getDefaultSkin(), false, true); + scrollText = new ScrollText("...", "...", core.getSkinSkin(), false, true); scrollText.setWidth(0.5f*getWidth()); scrollText.setPosition(15, getHeight() - scrollText.getHeight()-25f); addActor(scrollText); @@ -111,21 +110,8 @@ public class MainPage extends Page implements Observer { @Override public void update(Observable o, Object arg) { - if (o == mlc.getMusicList() && mlc.getMusicList().isSearched()) { - mlc.shuffle(true); - MusicManager mm = mlc.getCurrentMusicManager(); - updateVisualsForDifferentSong(mm); - mMenu.getMusicSelectionPage().refreshUIList(); - } else if (o == mlc) { - MusicManager mm = mlc.getCurrentMusicManager(); - mlc.play(); - updateVisualsForDifferentSong(mm); + if (o == mc && arg == MusicController.States.Loaded) { + scrollText.setText("Currently playing: " + mc.getCurrentSongName(), null); } - - } - - public void updateVisualsForDifferentSong(MusicManager mm) { - titleBar.getHvisual().setMM(mm); - scrollText.setText("Currently playing: " + mm.getBasicSongName(), null); } } diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/MusicSelectionPage.java b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/MusicSelectionPage.java index d953824..d76f449 100755 --- a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/MusicSelectionPage.java +++ b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/MusicSelectionPage.java @@ -26,17 +26,17 @@ import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; import com.badlogic.gdx.utils.Array; import zero1hd.rhythmbullet.audio.MusicInfo; +import zero1hd.rhythmbullet.audio.MusicMetadataController; +import zero1hd.rhythmbullet.audio.MusicController; import zero1hd.rhythmbullet.audio.MusicManager; -import zero1hd.rhythmbullet.desktop.audio.MusicInfoController; -import zero1hd.rhythmbullet.desktop.audio.MusicListController; import zero1hd.rhythmbullet.desktop.graphics.ui.components.MusicSelectable; import zero1hd.rhythmbullet.graphics.ui.components.ScrollText; public class MusicSelectionPage extends Page implements Observer { Preferences musicFileAnnotation; - private MusicListController mc; - private MusicInfoController mic; + private MusicController mc; + private MusicMetadataController mic; private Array selectables; private Table musicTable; private ScrollPane musicTableScrollPane; @@ -65,7 +65,7 @@ public class MusicSelectionPage extends Page implements Observer { private int uiSongInfoCount; private float scrollTimer, scrollDelay = 0.2f, scrollDelMod, songSelectionTimer; - public MusicSelectionPage(Skin skin, MusicListController musicListController, MusicInfoController musicInfoController, AssetManager assetManager, final Vector3 cameraTarget, final AnalysisPage ap) { + public MusicSelectionPage(Skin skin, MusicController musicListController, MusicMetadataController musicInfoController, AssetManager assetManager, final Vector3 cameraTarget, final AnalysisPage ap) { this.assets = assetManager; this.skin = skin; this.mc = musicListController; @@ -139,7 +139,7 @@ public class MusicSelectionPage extends Page implements Observer { public void changed(ChangeEvent event, Actor actor) { if (getSelectedMusic() != null) { cameraTarget.x = 2.5f*getWidth(); - ap.processSong(mc.getMusicList().getAudioData(getSelectedMusic()), (albumCoverTexture != null ? albumCoverTexture : assets.get("defaultCover.png", Texture.class)), mic.getInfo(getSelectedMusic())); + ap.processSong(mc.getMusicList().newAudioProcessor(getSelectedMusic()), (albumCoverTexture != null ? albumCoverTexture : assets.get("defaultCover.png", Texture.class)), mic.getInfo(getSelectedMusic())); } } }); @@ -195,7 +195,7 @@ public class MusicSelectionPage extends Page implements Observer { selectMusicUI(mc.getCurrentMusicManager()); } } else if (uiSongInfoCount < selectables.size && mic.isDone()) { - selectables.get(uiSongInfoCount).updateInfo(mic.getSongInfoArray().get(uiSongInfoCount)); + selectables.get(uiSongInfoCount).updateInfo(mic.getMetadataArray().get(uiSongInfoCount)); uiSongInfoCount++; if (uiSongInfoCount == selectables.size) { updateInformation(); @@ -291,9 +291,8 @@ public class MusicSelectionPage extends Page implements Observer { @Override public void update(Observable o, Object arg) { - if (o == mc) { - MusicManager mm = (MusicManager) arg; - selectMusicUI(mm); + if (o == mc && arg == MusicController.States.Loaded) { + selectMusicUI(mc.getCurrentMusic()); } } diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/OptionsPage.java b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/OptionsPage.java index 9f340db..56ce12f 100755 --- a/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/OptionsPage.java +++ b/desktop/src/zero1hd/rhythmbullet/desktop/graphics/ui/pages/OptionsPage.java @@ -14,7 +14,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextField; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import zero1hd.rhythmbullet.RhythmBullet; -import zero1hd.rhythmbullet.desktop.audio.MusicListController; +import zero1hd.rhythmbullet.audio.MusicController; public class OptionsPage extends Page { Table optionsTable; @@ -23,11 +23,11 @@ public class OptionsPage extends Page { private TextField directoryField; private float musicSearchTimer; - public OptionsPage(final RhythmBullet core, final Vector3 targetPosition, KeybindOptionsPage moreOptionsPage, MusicListController mlc) { - super("General", core.getDefaultSkin()); + public OptionsPage(final RhythmBullet core, final Vector3 targetPosition, KeybindOptionsPage moreOptionsPage, MusicController mlc) { + super("General", core.getSkinSkin()); //Back button - TextButton backButton = new TextButton("Back", core.getDefaultSkin()); + TextButton backButton = new TextButton("Back", core.getSkinSkin()); backButton.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -43,12 +43,12 @@ public class OptionsPage extends Page { optionsTable.setSize(getWidth(), getHeight()); addActor(optionsTable); - Label musicVolSliderLabel = new Label("Music Volume: ", core.getDefaultSkin()); + Label musicVolSliderLabel = new Label("Music Volume: ", core.getSkinSkin()); optionsTable.add(musicVolSliderLabel); - musicVolSlider = new Slider(0, 100, 0.1f, false, core.getDefaultSkin()); + musicVolSlider = new Slider(0, 100, 0.1f, false, core.getSkinSkin()); musicVolSlider.setValue(core.getPrefs().getFloat("music vol", 100f)*100f); optionsTable.add(musicVolSlider).minWidth(0.3f*getWidth()); - final Label musicVolPercentage = new Label(MathUtils.round(musicVolSlider.getValue()) + "%", core.getDefaultSkin()); + final Label musicVolPercentage = new Label(MathUtils.round(musicVolSlider.getValue()) + "%", core.getSkinSkin()); musicVolSlider.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -62,12 +62,12 @@ public class OptionsPage extends Page { optionsTable.row(); - Label fxVolSliderLabel = new Label("FX Volume: ", core.getDefaultSkin()); + Label fxVolSliderLabel = new Label("FX Volume: ", core.getSkinSkin()); optionsTable.add(fxVolSliderLabel); - fxVolSlider = new Slider(0, 100, 0.1f, false, core.getDefaultSkin()); + fxVolSlider = new Slider(0, 100, 0.1f, false, core.getSkinSkin()); fxVolSlider.setValue(core.getPrefs().getFloat("fx vol", 100f)*100f); optionsTable.add(fxVolSlider).fillX(); - final Label fxVolPercentage = new Label(MathUtils.round(fxVolSlider.getValue()) + "%", core.getDefaultSkin()); + final Label fxVolPercentage = new Label(MathUtils.round(fxVolSlider.getValue()) + "%", core.getSkinSkin()); fxVolSlider.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -80,16 +80,16 @@ public class OptionsPage extends Page { optionsTable.row(); - Label musicDirectoryLabel = new Label("Music Directory: ", core.getDefaultSkin()); + Label musicDirectoryLabel = new Label("Music Directory: ", core.getSkinSkin()); optionsTable.add(musicDirectoryLabel); - directoryField = new TextField(null, core.getDefaultSkin() ) { + directoryField = new TextField(null, core.getSkinSkin() ) { @Override public void act(float delta) { if (musicSearchTimer > 0) { musicSearchTimer -= delta; if (musicSearchTimer <= 0) { mlc.getMusicList().setSearchPath(directoryField.getText()); - mlc.getMusicList().asynchRefresh(); + mlc.getMusicList().asyncSearch(); } } super.act(delta); @@ -106,7 +106,7 @@ public class OptionsPage extends Page { optionsTable.row(); - TextButton keybindSettings = new TextButton("Set Controls", core.getDefaultSkin()); + TextButton keybindSettings = new TextButton("Set Controls", core.getSkinSkin()); keybindSettings.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -117,7 +117,7 @@ public class OptionsPage extends Page { optionsTable.row(); - TextButton graphicsSettings = new TextButton("Graphics", core.getDefaultSkin()); + TextButton graphicsSettings = new TextButton("Graphics", core.getSkinSkin()); graphicsSettings.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -128,7 +128,7 @@ public class OptionsPage extends Page { optionsTable.row(); - Label fpsLabel = new Label("", core.getDefaultSkin()) { + Label fpsLabel = new Label("", core.getSkinSkin()) { @Override public void act(float delta) { setText("Current Frames Per Second: " + Gdx.graphics.getFramesPerSecond()); @@ -139,7 +139,7 @@ public class OptionsPage extends Page { optionsTable.row(); - Label usageLabel = new Label("Current usage (lower the better): " + 100f*((float)(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())/(float)Runtime.getRuntime().totalMemory()) + "%", core.getDefaultSkin()) { + Label usageLabel = new Label("Current usage (lower the better): " + 100f*((float)(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())/(float)Runtime.getRuntime().totalMemory()) + "%", core.getSkinSkin()) { float refreshTime = 60; @Override public void act(float delta) { diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/screens/MainMenuScreen.java b/desktop/src/zero1hd/rhythmbullet/desktop/screens/MainScreen.java similarity index 88% rename from desktop/src/zero1hd/rhythmbullet/desktop/screens/MainMenuScreen.java rename to desktop/src/zero1hd/rhythmbullet/desktop/screens/MainScreen.java index afa44c7..318a0d1 100755 --- a/desktop/src/zero1hd/rhythmbullet/desktop/screens/MainMenuScreen.java +++ b/desktop/src/zero1hd/rhythmbullet/desktop/screens/MainScreen.java @@ -20,10 +20,10 @@ import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.utils.viewport.ScreenViewport; import zero1hd.rhythmbullet.RhythmBullet; -import zero1hd.rhythmbullet.audio.MusicManager; -import zero1hd.rhythmbullet.desktop.audio.MusicInfoController; -import zero1hd.rhythmbullet.desktop.audio.MusicList; -import zero1hd.rhythmbullet.desktop.audio.MusicListController; +import zero1hd.rhythmbullet.audio.MusicMetadataController; +import zero1hd.rhythmbullet.audio.MusicList; +import zero1hd.rhythmbullet.audio.MusicController; +import zero1hd.rhythmbullet.desktop.audio.processor.DesktopAudioProcessorFactory; import zero1hd.rhythmbullet.desktop.graphics.ui.pages.AnalysisPage; import zero1hd.rhythmbullet.desktop.graphics.ui.pages.CreditsPage; import zero1hd.rhythmbullet.desktop.graphics.ui.pages.KeybindOptionsPage; @@ -31,9 +31,9 @@ import zero1hd.rhythmbullet.desktop.graphics.ui.pages.MainPage; import zero1hd.rhythmbullet.desktop.graphics.ui.pages.MusicSelectionPage; import zero1hd.rhythmbullet.desktop.graphics.ui.pages.OptionsPage; import zero1hd.rhythmbullet.desktop.graphics.ui.pages.GraphicsOptionsPage; -import zero1hd.rhythmbullet.util.AdvancedResizeScreen; +import zero1hd.rhythmbullet.util.ResizeReadyScreen; -public class MainMenuScreen extends ScreenAdapter implements AdvancedResizeScreen { +public class MainScreen extends ScreenAdapter implements ResizeReadyScreen { public Stage stage; private Vector3 cameraPosition; @@ -46,8 +46,8 @@ public class MainMenuScreen extends ScreenAdapter implements AdvancedResizeScree private AnalysisPage analysisPage; private RhythmBullet core; - private MusicListController mlc; - private MusicInfoController mic; + private MusicController mlc; + private MusicMetadataController mmc; private float lerpAlpha; @@ -66,19 +66,18 @@ public class MainMenuScreen extends ScreenAdapter implements AdvancedResizeScree private Batch screenBatch; private ScreenViewport screenViewport; - public MainMenuScreen(RhythmBullet core) { + public MainScreen(RhythmBullet core) { this.core = core; stage = new Stage(new ScreenViewport()); cameraPosition = new Vector3(stage.getCamera().position); - MusicList musicList = new MusicList(); + MusicList musicList = new MusicList(new DesktopAudioProcessorFactory()); musicList.setSearchPath(core.getPrefs().getString("music dir")); - musicList.asynchRefresh(); - mlc = new MusicListController(musicList, core.getPrefs()); + mlc = new MusicController(musicList, core.getPrefs()); mlc.setAutoPlay(true); mlc.setShuffle(true); - mic = new MusicInfoController(musicList); + mmc = new MusicMetadataController(musicList); } @Override @@ -105,7 +104,7 @@ public class MainMenuScreen extends ScreenAdapter implements AdvancedResizeScree fboRegion.setTexture(normalBuffer.getColorBufferTexture()); screenBatch.setShader(brightFilterShader); screenBatch.setProjectionMatrix(screenViewport.getCamera().combined); - screenBatch.begin(); //BATCH STARTS HERE + screenBatch.begin(); //SCREEN BATCH STARTS HERE screenBatch.draw(fboRegion, 0, 0, stage.getWidth(), stage.getHeight()); screenBatch.flush(); lightFilterBuffer.end(); @@ -180,19 +179,21 @@ public class MainMenuScreen extends ScreenAdapter implements AdvancedResizeScree @Override public void postAssetLoad() { + mlc.deleteObservers(); + background = core.getAssetManager().get("backgrounds/mainBG.png", Texture.class); screenBatch = new SpriteBatch(); - + mainPage = new MainPage(core, cameraPosition, mlc, this); mainPage.setPosition(0, 0); stage.addActor(mainPage); //End main menu - keybindPage = new KeybindOptionsPage(core.getDefaultSkin(), core.getAssetManager(), cameraPosition); + keybindPage = new KeybindOptionsPage(core.getSkinSkin(), core.getAssetManager(), cameraPosition); keybindPage.setPosition(-1f*Gdx.graphics.getWidth(), -1f*Gdx.graphics.getHeight()); stage.addActor(keybindPage); - graphicsPage = new GraphicsOptionsPage(core.getDefaultSkin(), core.getPrefs(), this, core.getAssetManager()); + graphicsPage = new GraphicsOptionsPage(core.getSkinSkin(), core.getPrefs(), this, core.getAssetManager()); graphicsPage.setPosition(-1f*Gdx.graphics.getWidth(), 1f*Gdx.graphics.getHeight()); stage.addActor(graphicsPage); @@ -201,7 +202,7 @@ public class MainMenuScreen extends ScreenAdapter implements AdvancedResizeScree optionsPage.setPosition(-Gdx.graphics.getWidth(), 0); stage.addActor(optionsPage); - creditsPage = new CreditsPage(core.getDefaultSkin()); + creditsPage = new CreditsPage(core.getSkinSkin()); creditsPage.setPosition(0, Gdx.graphics.getHeight()); stage.addActor(creditsPage); @@ -209,7 +210,7 @@ public class MainMenuScreen extends ScreenAdapter implements AdvancedResizeScree analysisPage.setPosition(2*Gdx.graphics.getWidth(), 0f); stage.addActor(analysisPage); - musicSelectionPage = new MusicSelectionPage(core.getDefaultSkin(), mlc, mic, core.getAssetManager(), cameraPosition, analysisPage); + musicSelectionPage = new MusicSelectionPage(core.getSkinSkin(), mlc, mmc, core.getAssetManager(), cameraPosition, analysisPage); musicSelectionPage.setPosition(1f*Gdx.graphics.getWidth(), 0f); stage.addActor(musicSelectionPage); stage.addListener(new InputListener() { @@ -233,17 +234,12 @@ public class MainMenuScreen extends ScreenAdapter implements AdvancedResizeScree super.clicked(event, x, y); } }); - mlc.getMusicList().deleteObservers(); - mlc.deleteObservers(); + mlc.addObserver(musicSelectionPage); mlc.addObserver(mainPage); - mlc.getMusicList().addObserver(mainPage); - if (mlc.getMusicList().isSearched() && mlc.getCurrentMusicManager() != null) { - MusicManager mManager = mlc.getCurrentMusicManager(); - mainPage.updateVisualsForDifferentSong(mManager); - musicSelectionPage.refreshUIList(); - } + mlc.getMusicList().asyncSearch(); + } @Override @@ -281,7 +277,7 @@ public class MainMenuScreen extends ScreenAdapter implements AdvancedResizeScree if (gaussianBlurShader != null) { dismantleShaders(); } - mic.dispose(); + mmc.dispose(); screenBatch.dispose(); super.dispose(); } diff --git a/desktop/src/zero1hd/rhythmbullet/desktop/screens/SplashScreen.java b/desktop/src/zero1hd/rhythmbullet/desktop/screens/SplashScreen.java index c73b1c5..b745b21 100755 --- a/desktop/src/zero1hd/rhythmbullet/desktop/screens/SplashScreen.java +++ b/desktop/src/zero1hd/rhythmbullet/desktop/screens/SplashScreen.java @@ -1,6 +1,7 @@ package zero1hd.rhythmbullet.desktop.screens; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Screen; import com.badlogic.gdx.ScreenAdapter; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; @@ -10,18 +11,21 @@ import com.badlogic.gdx.scenes.scene2d.actions.Actions; import com.badlogic.gdx.scenes.scene2d.ui.Image; import com.badlogic.gdx.utils.viewport.ScreenViewport; +import zero1hd.rhythmbullet.InitialScreen; import zero1hd.rhythmbullet.RhythmBullet; -import zero1hd.rhythmbullet.util.AdvancedResizeScreen; +import zero1hd.rhythmbullet.util.ResizeReadyScreen; -public class SplashScreen extends ScreenAdapter implements AdvancedResizeScreen { +public class SplashScreen extends ScreenAdapter implements ResizeReadyScreen, InitialScreen { private Stage stage; - private RhythmBullet core; private Texture splash; private Image zero1HD; - private boolean done; - public SplashScreen(RhythmBullet core) { - this.core = core; + public SplashScreen() { + splash = new Texture(Gdx.files.internal("splashlogo.png")); + zero1HD = new Image(splash); + zero1HD.setScale((Gdx.graphics.getHeight()*0.8f)/zero1HD.getHeight()); + zero1HD.setColor(0f,1f,1f,0.1f); + stage.addActor(zero1HD); } @Override @@ -34,49 +38,31 @@ public class SplashScreen extends ScreenAdapter implements AdvancedResizeScreen Gdx.gl.glClearColor(1f, 1f, 1f, 1f); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); stage.act(delta); - - if (!zero1HD.hasActions() && core.isInitComplete()) { - attemptMoveOn(); - } - stage.draw(); super.render(delta); } - private void attemptMoveOn() { - if (!done) { - Gdx.app.debug("Loading Screen", "queue has all been loaded. Action is done playing."); - done = true; - core.setScreen(new MainMenuScreen(core)); - zero1HD.remove(); - } - } - @Override public void hide() { - core.setInitComplete(); splash.dispose(); super.hide(); } @Override public void preAssetLoad() { - if (stage != null) { - stage.dispose(); - splash.dispose(); - } } @Override public void postAssetLoad() { stage = new Stage(new ScreenViewport()); - splash = new Texture(Gdx.files.internal("splashlogo.png")); - zero1HD = new Image(splash); zero1HD.setScale((Gdx.graphics.getHeight()*0.8f)/zero1HD.getHeight()); - zero1HD.setColor(0f,1f,1f,0f); - stage.addActor(zero1HD); zero1HD.setPosition((stage.getWidth() - zero1HD.getWidth()*zero1HD.getScaleX())/2f, (stage.getHeight() - zero1HD.getHeight()*zero1HD.getScaleY())/2f); zero1HD.addAction(Actions.sequence(Actions.color(Color.WHITE, 1f), Actions.fadeOut(0.5f))); } + + @Override + public Screen createMainScreen(RhythmBullet game) { + return new MainScreen(game); + } }