diff --git a/core/src/zero1hd/polyjet/audio/AudioAnalyzer.java b/core/src/zero1hd/polyjet/audio/AudioAnalyzer.java index 5071d48..c39a42b 100755 --- a/core/src/zero1hd/polyjet/audio/AudioAnalyzer.java +++ b/core/src/zero1hd/polyjet/audio/AudioAnalyzer.java @@ -1,15 +1,16 @@ package zero1hd.polyjet.audio; -import org.jaudiotagger.audio.AudioFile; - import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.FloatArray; import edu.emory.mathcs.jtransforms.fft.FloatFFT_1D; +import zero1hd.polyjet.util.MiniEvents; +import zero1hd.polyjet.util.MiniListener; public class AudioAnalyzer { private boolean containsData; - + private boolean finalized; FloatFFT_1D fft; public AudioData audiofile; @@ -44,9 +45,12 @@ public class AudioAnalyzer { int UMThresholdCalcRange; int bassThresholdCalcRange; + private Array listeners; private volatile int progress; public AudioAnalyzer() { + listeners = new Array<>(); + analysisAlgorithm = new Runnable() { @Override @@ -108,6 +112,8 @@ public class AudioAnalyzer { shrinkData(); containsData = true; + + send(MiniEvents.SPECTRAL_FLUX_DONE); } }; @@ -188,6 +194,8 @@ public class AudioAnalyzer { } Gdx.app.debug("Audio Analyzer", "overlapped beats checked."); + + finalized = true; } }; @@ -242,6 +250,11 @@ public class AudioAnalyzer { thresholdClean.start(); } + public void runThresholdCleaning() { + Thread thresholdClean = new Thread(thresholdCalculator); + thresholdClean.start(); + } + public FloatArray getBassPeaks() { return bassPeaks; } @@ -287,4 +300,18 @@ public class AudioAnalyzer { public synchronized int getProgress() { return progress; } + + public boolean isFinalized() { + return finalized; + } + + public void addListener(MiniListener listener) { + listeners.add(listener); + } + + public void send(MiniEvents ID) { + while (listeners.iterator().hasNext()) { + listeners.iterator().next().handle(ID); + } + } } diff --git a/core/src/zero1hd/polyjet/audio/AudioInfo.java b/core/src/zero1hd/polyjet/audio/AudioInfo.java index 8117095..1509c93 100755 --- a/core/src/zero1hd/polyjet/audio/AudioInfo.java +++ b/core/src/zero1hd/polyjet/audio/AudioInfo.java @@ -46,6 +46,8 @@ public class AudioInfo implements Disposable { e.printStackTrace(); } + invalidMusic = true; + } else { try { diff --git a/core/src/zero1hd/polyjet/ui/builders/MusicSelectable.java b/core/src/zero1hd/polyjet/ui/builders/MusicSelectable.java index 7035069..616edf5 100755 --- a/core/src/zero1hd/polyjet/ui/builders/MusicSelectable.java +++ b/core/src/zero1hd/polyjet/ui/builders/MusicSelectable.java @@ -101,4 +101,8 @@ public class MusicSelectable extends Button implements Disposable { audioInfo.dispose(); } + public boolean isMusicInvalid() { + return audioInfo.isInvalidMusic(); + } + } diff --git a/core/src/zero1hd/polyjet/ui/pages/MusicSelectionPage.java b/core/src/zero1hd/polyjet/ui/pages/MusicSelectionPage.java index 8582f1c..6313dfc 100755 --- a/core/src/zero1hd/polyjet/ui/pages/MusicSelectionPage.java +++ b/core/src/zero1hd/polyjet/ui/pages/MusicSelectionPage.java @@ -106,10 +106,14 @@ public class MusicSelectionPage extends Page { selectable.addInfoToPanel(musicChoiceScroller, panelWidthCalc(getWidth()) - 20f); selectable.addListener(new ChangeListener() { - @Override public void changed(ChangeEvent event, Actor actor) { - ap.setSong(Audio.getAudioData(selectable.getMusicFile()), selectable.getAudioInfo()); + + if (!selectable.isMusicInvalid()) { + ap.setSong(Audio.getAudioData(selectable.getMusicFile()), selectable.getAudioInfo()); + } else { + //Play "no" sound + } } }); } diff --git a/core/src/zero1hd/polyjet/ui/stages/CreativeStage.java b/core/src/zero1hd/polyjet/ui/stages/CreativeStage.java index 2a70b34..9bf22d0 100755 --- a/core/src/zero1hd/polyjet/ui/stages/CreativeStage.java +++ b/core/src/zero1hd/polyjet/ui/stages/CreativeStage.java @@ -24,11 +24,14 @@ import zero1hd.polyjet.ui.windows.GraphWindow; import zero1hd.polyjet.ui.windows.MusicController; import zero1hd.polyjet.ui.windows.MusicSelector; import zero1hd.polyjet.ui.windows.VolumeWindow; +import zero1hd.polyjet.util.MiniEvents; +import zero1hd.polyjet.util.MiniListener; -public class CreativeStage extends Stage { +public class CreativeStage extends Stage implements MiniListener { MusicController musicPlayBackControls; MusicSelector musicSelector; FPSWindow fpsViewer; + BeatViewer beatViewer; GraphWindow graphViewer; VolumeWindow volumeWindow; @@ -36,17 +39,22 @@ public class CreativeStage extends Stage { AudioAnalyzer analyzer; Window toolbox; Polyjet core; - boolean postAnalysisComplete; private AudioData audioWrapper; public CreativeStage(final Polyjet core, final MainMenu mainMenu) { this.core = core; analyzer = new AudioAnalyzer(); + analyzer.addListener(this); + musicSelector = new MusicSelector("Select Audio File", core.getDefaultSkin(), core.prefs.getString("music dir"), "default"); + musicSelector.addListener(this); musicSelector.postInit(); musicSelector.refresh(); + fpsViewer = new FPSWindow("FPS", core.getDefaultSkin()); + beatViewer = new BeatViewer("Beat", core.getDefaultSkin(), core, analyzer); + graphViewer = new GraphWindow("Peak Values", core.getDefaultSkin()); volumeWindow = new VolumeWindow("Volume adjustments", core.getDefaultSkin(), core.prefs); @@ -85,6 +93,7 @@ public class CreativeStage extends Stage { toolboxToolSet.add(musicSelectorCheckbox); toolboxToolSet.row(); + musicPlayBackControls = new MusicController(core.getDefaultSkin()); final CheckBox musicPlayBackCheckbox = new CheckBox(" Playback controls", core.getDefaultSkin()); musicPlayBackCheckbox.addListener(new ChangeListener() { @@ -178,34 +187,9 @@ public class CreativeStage extends Stage { @Override public void act(float delta) { - if (musicSelector.isConfirmed()) { - audioWrapper = Audio.getAudioData(musicSelector.getSelectedMusic()); - audioWrapper.getPlaybackMusic().setVolume(core.prefs.getFloat("music vol")/100f); - analyzer.resetVars(); - analyzer.startAnalyticalThread(audioWrapper); - musicPlayBackControls.setMusicReady(false); - beatViewer.setMusicReady(false); - graphViewer.setData(analyzer.getBassPeaks(), analyzer.getUMPeaks()); - postAnalysisComplete = false; + if (musicPlayBackControls.getAudiofile() != null) { + musicPlayBackControls.getAudiofile().readIndexUpdate(); } - - if (!postAnalysisComplete && analyzer.containsData()) { - postAnalysisComplete = true; - musicPlayBackControls.setMusicReady(true); - beatViewer.setMusicReady(true); - - } - - if (analyzer.audiofile != null) { - if (volumeWindow.isUpdateRequired()) { - analyzer.audiofile.getPlaybackMusic().setVolume(core.prefs.getFloat("music vol")/100f); - } - - analyzer.audiofile.readIndexUpdate(); - beatViewer.setSongIndex(analyzer.getReadIndex()); - graphViewer.getGraph().setAudioDataIndex(analyzer.getReadIndex()); - } - super.act(delta); } @Override @@ -215,5 +199,25 @@ public class CreativeStage extends Stage { audioWrapper.reset(); super.dispose(); } - + + @Override + public void handle(MiniEvents ID) { + switch (ID) { + case MUSIC_SELECTED: + beatViewer.setMusic(null); + volumeWindow.setMusic(null); + graphViewer.setData(null, null, null); + musicPlayBackControls.setAudiofile(null); + analyzer.startAnalyticalThread(Audio.getAudioData(musicSelector.getSelectedMusic())); + break; + case SPECTRAL_FLUX_DONE: + analyzer.runThresholdCleaning(); + break; + case MUSIC_DATA_CLEANED: + musicPlayBackControls.setAudiofile(Audio.getAudioData(musicSelector.getSelectedMusic())); + volumeWindow.setMusic(musicPlayBackControls.getAudiofile()); + beatViewer.setMusic(musicPlayBackControls.getAudiofile()); + graphViewer.setData(analyzer.getBassPeaks(), analyzer.getUMPeaks(), musicPlayBackControls.getAudiofile()); + } + } } diff --git a/core/src/zero1hd/polyjet/ui/windows/BeatViewer.java b/core/src/zero1hd/polyjet/ui/windows/BeatViewer.java index a032dc0..7ab49ca 100755 --- a/core/src/zero1hd/polyjet/ui/windows/BeatViewer.java +++ b/core/src/zero1hd/polyjet/ui/windows/BeatViewer.java @@ -11,11 +11,12 @@ import com.badlogic.gdx.scenes.scene2d.ui.Window; import zero1hd.polyjet.Polyjet; import zero1hd.polyjet.audio.AudioAnalyzer; +import zero1hd.polyjet.audio.AudioData; public class BeatViewer extends Window { Pixmap lights; int songIndex; - boolean musicReady; + AudioData music; Texture lightOn; public BeatViewer(String title, Skin skin, Polyjet core, final AudioAnalyzer data) { @@ -39,7 +40,7 @@ public class BeatViewer extends Window { final Image bassBarFill = new Image(core.getDefaultSkin().getPatch("bar-fill")) { @Override public void act(float delta) { - if (musicReady && data.getBassPeaks().get(songIndex) >= 1f) { + if (music != null && data.getBassPeaks().get(songIndex) >= 1f) { clearActions(); addAction(Actions.sequence(Actions.sizeTo(getWidth(), (data.getBassPeaks().get(songIndex)/data.getBassMaxValue())*bgBassBar.getHeight()), Actions.sizeTo(getWidth(), 0, 0.3f))); } @@ -58,7 +59,7 @@ public class BeatViewer extends Window { Image UMBarFill = new Image(core.getDefaultSkin().getPatch("bar-fill")) { @Override public void act(float delta) { - if (musicReady && data.getUMPeaks().get(songIndex) >= 1f) { + if (music != null && data.getUMPeaks().get(songIndex) >= 1f) { clearActions(); addAction(Actions.sequence(Actions.sizeTo(getWidth(), (data.getUMPeaks().get(songIndex)/data.getUMMaxValue())*bgUMBar.getHeight()), Actions.sizeTo(getWidth(), 0f, 0.3f))); } @@ -76,7 +77,7 @@ public class BeatViewer extends Window { Image bassIndicator = new Image(lightOn) { @Override public void act(float delta) { - if (musicReady && data.getBassPeaks().get(songIndex) >= 2) { + if (music != null && data.getBassPeaks().get(songIndex) >= 2) { clearActions(); addAction(Actions.sequence(Actions.alpha(1f), Actions.fadeOut(0.15f))); } @@ -91,7 +92,7 @@ public class BeatViewer extends Window { Image UMIndicator = new Image(lightOn) { @Override public void act(float delta) { - if (musicReady && data.getUMPeaks().get(songIndex) >= 1) { + if (music != null && data.getUMPeaks().get(songIndex) >= 1) { clearActions(); addAction(Actions.sequence(Actions.alpha(1f), Actions.fadeOut(0.15f))); } @@ -102,11 +103,13 @@ public class BeatViewer extends Window { add(UMIndicator).center(); } - public void setSongIndex(int songIndex) { - this.songIndex = songIndex; + @Override + public void act(float delta) { + songIndex = music.getReadIndex(); + super.act(delta); } - public void setMusicReady(boolean musicReady) { - this.musicReady = musicReady; + public void setMusic(AudioData audioData) { + this.music = audioData; } } diff --git a/core/src/zero1hd/polyjet/ui/windows/GraphWindow.java b/core/src/zero1hd/polyjet/ui/windows/GraphWindow.java index 02261e0..a1e88bc 100755 --- a/core/src/zero1hd/polyjet/ui/windows/GraphWindow.java +++ b/core/src/zero1hd/polyjet/ui/windows/GraphWindow.java @@ -4,10 +4,12 @@ import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.ui.Window; import com.badlogic.gdx.utils.FloatArray; +import zero1hd.polyjet.audio.AudioData; import zero1hd.polyjet.ui.builders.AudioGraph; public class GraphWindow extends Window { AudioGraph graph; + AudioData audioData; public GraphWindow(String title, Skin skin) { super(title, skin); @@ -18,15 +20,13 @@ public class GraphWindow extends Window { @Override public void act(float delta) { + graph.setAudioDataIndex(audioData.getReadIndex()); super.act(delta); } - public void setData(FloatArray dataSet1, FloatArray dataSet2) { + public void setData(FloatArray dataSet1, FloatArray dataSet2, AudioData audioData) { + this.audioData = audioData; graph.setGraphingData(dataSet1, dataSet2); } - public AudioGraph getGraph() { - return graph; - } - } diff --git a/core/src/zero1hd/polyjet/ui/windows/MusicController.java b/core/src/zero1hd/polyjet/ui/windows/MusicController.java index af98e20..39b8d92 100755 --- a/core/src/zero1hd/polyjet/ui/windows/MusicController.java +++ b/core/src/zero1hd/polyjet/ui/windows/MusicController.java @@ -16,15 +16,13 @@ import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import zero1hd.polyjet.audio.AudioData; public class MusicController extends Window { - boolean musicReady; Skin skin; private Image togglePlay; private TextField info; private AudioData audiofile; - public MusicController(final Skin skin, final AudioData audiofile) { + public MusicController(final Skin skin) { super("Playback Controller", skin); - this.audiofile = audiofile; defaults().space(5f); @@ -49,7 +47,7 @@ public class MusicController extends Window { if (audiofile.getPlaybackMusic() != null) { if (audiofile.getPlaybackMusic().isPlaying()) { setDrawable(skin.getDrawable("pause")); - } else if (!audiofile.getPlaybackMusic().isPlaying() && musicReady) { + } else if (!audiofile.getPlaybackMusic().isPlaying() && audiofile != null) { setDrawable(skin.getDrawable("arrow")); } } @@ -63,7 +61,7 @@ public class MusicController extends Window { if (audiofile.getPlaybackMusic().isPlaying()) { audiofile.getPlaybackMusic().pause(); } else { - if (musicReady) { + if (audiofile != null) { audiofile.getPlaybackMusic().play(); } } @@ -115,9 +113,12 @@ public class MusicController extends Window { setSize(260, 75); } - public void setMusicReady(boolean musicReady) { - this.musicReady = musicReady; - if (!musicReady) { + + public void setAudiofile(AudioData audiofile) { + this.audiofile.reset(); + this.audiofile = audiofile; + + if (audiofile == null) { togglePlay.setDrawable(skin.getDrawable("loading")); info.setText("Analyzing..."); } else { @@ -126,11 +127,10 @@ public class MusicController extends Window { audiofile.getPlaybackMusic().play(); audiofile.getPlaybackMusic().pause(); } - } - @Override - public void act(float delta) { - // TODO Auto-generated method stub - super.act(delta); + } + + public AudioData getAudiofile() { + return audiofile; } } diff --git a/core/src/zero1hd/polyjet/ui/windows/MusicSelector.java b/core/src/zero1hd/polyjet/ui/windows/MusicSelector.java index 8fd35ce..d98f00e 100755 --- a/core/src/zero1hd/polyjet/ui/windows/MusicSelector.java +++ b/core/src/zero1hd/polyjet/ui/windows/MusicSelector.java @@ -11,6 +11,9 @@ import com.badlogic.gdx.scenes.scene2d.ui.Window; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.utils.Array; +import zero1hd.polyjet.util.MiniEvents; +import zero1hd.polyjet.util.MiniListener; + public class MusicSelector extends Window { boolean confirmed; boolean back; @@ -19,6 +22,9 @@ public class MusicSelector extends Window { private List musicList; private String path; private ScrollPane listScroller; + + private Array listeners; + public MusicSelector(String title, Skin skin, final String path, String listStyle) { super(title, skin); this.path = path; @@ -26,6 +32,8 @@ public class MusicSelector extends Window { padLeft(5f); padRight(5f); + listeners = new Array<>(); + setSize(Gdx.graphics.getWidth()*0.5f, Gdx.graphics.getHeight()*0.5f); fileNames = new Array<>(); @@ -38,6 +46,7 @@ public class MusicSelector extends Window { public void changed(ChangeEvent event, Actor actor) { confirmed = true; selectedMusic = Gdx.files.absolute(path+System.getProperty("file.separator")+musicList.getSelected()); + send(MiniEvents.MUSIC_SELECTED); } }); add(confirmButton).right(); @@ -80,4 +89,14 @@ public class MusicSelector extends Window { public FileHandle getSelectedMusic() { return selectedMusic; } + + private void send(MiniEvents ID) { + while (listeners.iterator().hasNext()) { + listeners.iterator().next().handle(ID); + } + } + + public void addListener(MiniListener handler) { + listeners.add(handler); + } } diff --git a/core/src/zero1hd/polyjet/ui/windows/VolumeWindow.java b/core/src/zero1hd/polyjet/ui/windows/VolumeWindow.java index 37567ec..faa614f 100755 --- a/core/src/zero1hd/polyjet/ui/windows/VolumeWindow.java +++ b/core/src/zero1hd/polyjet/ui/windows/VolumeWindow.java @@ -9,13 +9,15 @@ import com.badlogic.gdx.scenes.scene2d.ui.Slider; import com.badlogic.gdx.scenes.scene2d.ui.Window; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import zero1hd.polyjet.audio.AudioData; + public class VolumeWindow extends Window { private Slider fxVolSlider; private Slider musicVolSlider; private Preferences prefs; - boolean updateRequired; + private AudioData music; public VolumeWindow(String title, Skin skin, Preferences prefs) { super(title, skin); this.prefs = prefs; @@ -32,6 +34,9 @@ public class VolumeWindow extends Window { public void changed(ChangeEvent event, Actor actor) { save(); musicVolPercentage.setText(MathUtils.round(musicVolSlider.getValue()) + "%"); + if (music != null) { + music.getPlaybackMusic().setVolume(musicVolSlider.getValue()/100f); + } } }); @@ -59,13 +64,10 @@ public class VolumeWindow extends Window { public void save() { prefs.putFloat("music vol", musicVolSlider.getValue()); prefs.putFloat("fx vol", fxVolSlider.getValue()); - updateRequired = true; prefs.flush(); } - public boolean isUpdateRequired() { - boolean isUpdateRequired = updateRequired; - updateRequired = false; - return isUpdateRequired; + public void setMusic(AudioData music) { + this.music = music; } } diff --git a/core/src/zero1hd/polyjet/util/MiniEvents.java b/core/src/zero1hd/polyjet/util/MiniEvents.java new file mode 100755 index 0000000..e3ad664 --- /dev/null +++ b/core/src/zero1hd/polyjet/util/MiniEvents.java @@ -0,0 +1,5 @@ +package zero1hd.polyjet.util; + +public enum MiniEvents { + SPECTRAL_FLUX_DONE, MUSIC_DATA_CLEANED, MUSIC_SELECTED; +} diff --git a/core/src/zero1hd/polyjet/util/MiniListener.java b/core/src/zero1hd/polyjet/util/MiniListener.java new file mode 100755 index 0000000..8a09815 --- /dev/null +++ b/core/src/zero1hd/polyjet/util/MiniListener.java @@ -0,0 +1,5 @@ +package zero1hd.polyjet.util; + +public interface MiniListener { + public void handle(MiniEvents ID); +}