asynch song loading functional now

This commit is contained in:
Harrison Deng 2017-12-05 10:42:06 -06:00
parent 8f03c3310d
commit c41c941338
9 changed files with 106 additions and 166 deletions

View File

@ -5,6 +5,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
@ -56,6 +58,7 @@ public class Mp3Manager implements MusicManager {
exec = Executors.newSingleThreadExecutor(); exec = Executors.newSingleThreadExecutor();
exec.submit(() -> { exec.submit(() -> {
lock.lock(); lock.lock();
Logger.getLogger("org.jaudiotagger").setLevel(Level.OFF);
try { try {
MP3File mp3File = new MP3File(audioFile.file()); MP3File mp3File = new MP3File(audioFile.file());
sampleCount = MathUtils.round(Float.valueOf((float) (mp3File.getAudioHeader().getSampleRateAsNumber()*mp3File.getMP3AudioHeader().getPreciseTrackLength()))); sampleCount = MathUtils.round(Float.valueOf((float) (mp3File.getAudioHeader().getSampleRateAsNumber()*mp3File.getMP3AudioHeader().getPreciseTrackLength())));
@ -113,6 +116,7 @@ public class Mp3Manager implements MusicManager {
exec.shutdown(); exec.shutdown();
try { try {
bitstream.close(); bitstream.close();
bitstream = null;
} catch (BitstreamException e) { } catch (BitstreamException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -160,28 +164,32 @@ public class Mp3Manager implements MusicManager {
} }
public int loadNextBuffer() { public int loadNextBuffer() {
int bytesRead = 0; if (bitstream != null) {
try { int bytesRead = 0;
Header header = bitstream.readFrame(); try {
if (header != null) { Header header = bitstream.readFrame();
if (header != null) {
try { try {
decoder.decodeFrame(header, bitstream); decoder.decodeFrame(header, bitstream);
} catch (ArrayIndexOutOfBoundsException | DecoderException e) { } catch (ArrayIndexOutOfBoundsException | DecoderException e) {
System.out.println(e); System.out.println(e);
}
bitstream.closeFrame();
bytesRead = sampleBuffer.reset();
currentByteSet = sampleBuffer.getBuffer();
} else {
currentByteSet = null;
} }
} catch (BitstreamException e1) {
bitstream.closeFrame(); e1.printStackTrace();
bytesRead = sampleBuffer.reset();
currentByteSet = sampleBuffer.getBuffer();
} else {
currentByteSet = null;
} }
} catch (BitstreamException e1) { return bytesRead;
e1.printStackTrace(); } else {
return 0;
} }
return bytesRead;
} }
@Override @Override

View File

@ -1,6 +1,8 @@
package zero1hd.rhythmbullet.audio; package zero1hd.rhythmbullet.audio;
import java.util.Observable; import java.util.Observable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.files.FileHandle;
@ -14,9 +16,12 @@ public class MusicList extends Observable {
private String searchPath; private String searchPath;
private boolean searched; private boolean searched;
private FileHandleAlphabeticalComparator fhac; private FileHandleAlphabeticalComparator fhac;
private ExecutorService exec;
public MusicList() { public MusicList() {
musicList = new Array<>(); musicList = new Array<>();
fhac = new FileHandleAlphabeticalComparator(); fhac = new FileHandleAlphabeticalComparator();
exec = Executors.newSingleThreadExecutor();
} }
private Array<FileHandle> recursiveMusicFileList(FileHandle fileHandle) { private Array<FileHandle> recursiveMusicFileList(FileHandle fileHandle) {
@ -34,8 +39,11 @@ public class MusicList extends Observable {
return musicFiles; return musicFiles;
} }
public void refresh() { /**
searched = true; * refreshes song list, notifies any observers of the refresh while passing no argument to the notifier.
* Blocking.
*/
public void refresh(boolean notify) {
musicList.clear(); musicList.clear();
Gdx.app.debug("SongController", "Searching path: " + searchPath); Gdx.app.debug("SongController", "Searching path: " + searchPath);
if (Gdx.files.absolute(searchPath).exists() && Gdx.files.absolute(searchPath).isDirectory()) { if (Gdx.files.absolute(searchPath).exists() && Gdx.files.absolute(searchPath).isDirectory()) {
@ -47,7 +55,26 @@ public class MusicList extends Observable {
musicList.add(Gdx.files.external("RhythmBullet/Alan Walker - Spectre.mp3")); musicList.add(Gdx.files.external("RhythmBullet/Alan Walker - Spectre.mp3"));
Sort.instance().sort(musicList, fhac); Sort.instance().sort(musicList, fhac);
notifyObservers(); searched = true;
if (notify) {
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.postRunnable(() -> {
notifyObservers();
searched = true;
Gdx.app.debug("Asynch-MusicList", "Async refresh done. Notification has been sent.");
});
});
} }
public void setSearchPath(String searchPath) { public void setSearchPath(String searchPath) {

View File

@ -1,6 +1,5 @@
package zero1hd.rhythmbullet.audio; package zero1hd.rhythmbullet.audio;
import java.security.InvalidParameterException;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.Random; import java.util.Random;
@ -22,22 +21,24 @@ public class MusicListController extends Observable implements OnCompletionListe
public MusicListController(MusicList musicList, Preferences prefs) { public MusicListController(MusicList musicList, Preferences prefs) {
if (prefs == null) throw new NullPointerException("preferences can't be null..."); if (prefs == null) throw new NullPointerException("preferences can't be null...");
if (musicList == null) throw new NullPointerException("music list can't be null..."); if (musicList == null) throw new NullPointerException("music list can't be null...");
if (!musicList.isSearched()) throw new InvalidParameterException("music list has to be searched already.");
musicList.addObserver(this); musicList.addObserver(this);
this.prefs = prefs; this.prefs = prefs;
this.musicList = musicList; this.musicList = musicList;
rand = new Random(); rand = new Random();
changeMusic();
} }
public void play() { public void play() {
mm.play(); if (mm != null) {
mm.setVolume(prefs.getFloat("music vol", 1f)); mm.play();
mm.setVolume(prefs.getFloat("music vol", 1f));
} else {
Gdx.app.debug("MusicListController", "failed to begin playing. Load the music!!!");
}
} }
public void setMusicByIndex(int index) { public void setMusicByIndex(int index) {
this.currentPlaybackID = index; this.currentPlaybackID = index;
changeMusic(); loadMusic();
} }
public void skip() { public void skip() {
@ -45,7 +46,7 @@ public class MusicListController extends Observable implements OnCompletionListe
if (shuffle) { if (shuffle) {
shuffle(false); shuffle(false);
} }
changeMusic(); loadMusic();
} }
public void previous() { public void previous() {
@ -53,7 +54,7 @@ public class MusicListController extends Observable implements OnCompletionListe
if (shuffle) { if (shuffle) {
shuffle(false); shuffle(false);
} }
changeMusic(); loadMusic();
} }
@Override @Override
@ -68,7 +69,7 @@ public class MusicListController extends Observable implements OnCompletionListe
} else { } else {
currentPlaybackID++; currentPlaybackID++;
} }
changeMusic(); loadMusic();
play(); play();
} }
} }
@ -84,7 +85,7 @@ public class MusicListController extends Observable implements OnCompletionListe
currentPlaybackID = rand.nextInt(musicList.getAmountOfMusic()); currentPlaybackID = rand.nextInt(musicList.getAmountOfMusic());
} }
if (load) { if (load) {
changeMusic(); loadMusic();
} }
} }
@ -104,7 +105,11 @@ public class MusicListController extends Observable implements OnCompletionListe
return autoPlay; return autoPlay;
} }
private void changeMusic() { /**
* Loads the current selected song.
*/
public void loadMusic() {
Gdx.app.debug("MusicListController", "music is being loaded...");
if (mm != null) { if (mm != null) {
mm.dispose(); mm.dispose();
} }
@ -133,7 +138,7 @@ public class MusicListController extends Observable implements OnCompletionListe
@Override @Override
public void update(Observable o, Object arg) { public void update(Observable o, Object arg) {
if (o == musicList) { if (o == musicList) {
changeMusic(); loadMusic();
play(); play();
} }
} }

View File

@ -10,21 +10,20 @@ import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import zero1hd.rhythmbullet.audio.MusicListController; import zero1hd.rhythmbullet.audio.MusicListController;
public class MusicControls extends HorizontalGroup { public class MusicControls extends HorizontalGroup {
private MusicListController sc;
private ImageButton reverse, forward; private ImageButton reverse, forward;
private CheckBox shuffle, play; private CheckBox shuffle, play;
private float disableTimer; private float disableTimer;
public MusicControls(Skin skin, MusicListController sc) { public MusicControls(Skin skin, MusicListController sc) {
this.sc = sc;
reverse = new ImageButton(skin, "rewind-button"); reverse = new ImageButton(skin, "rewind-button");
reverse.addListener(new ChangeListener() { reverse.addListener(new ChangeListener() {
@Override @Override
public void changed(ChangeEvent event, Actor actor) { public void changed(ChangeEvent event, Actor actor) {
boolean wasPlaying = sc.getCurrentMusicManager().isPlaying(); if (sc.getCurrentMusicManager() != null) {
sc.previous(); boolean wasPlaying = sc.getCurrentMusicManager().isPlaying();
if (wasPlaying) { sc.previous();
sc.play(); if (wasPlaying) {
sc.play();
}
} }
forward.setDisabled(true); forward.setDisabled(true);
@ -37,17 +36,23 @@ public class MusicControls extends HorizontalGroup {
play = new CheckBox(null, skin, "play-button") { play = new CheckBox(null, skin, "play-button") {
@Override @Override
public void act(float delta) { public void act(float delta) {
play.setChecked(sc.getCurrentMusicManager().isPlaying()); if (sc.getCurrentMusicManager() != null) {
play.setChecked(sc.getCurrentMusicManager().isPlaying());
} else {
play.setChecked(false);
}
super.act(delta); super.act(delta);
} }
}; };
play.addListener(new ChangeListener() { play.addListener(new ChangeListener() {
@Override @Override
public void changed(ChangeEvent event, Actor actor) { public void changed(ChangeEvent event, Actor actor) {
if (play.isChecked()) { if (sc.getCurrentMusicManager() != null) {
sc.getCurrentMusicManager().play(); if (play.isChecked()) {
} else { sc.getCurrentMusicManager().play();
sc.getCurrentMusicManager().pause(); } else {
sc.getCurrentMusicManager().pause();
}
} }
} }
}); });
@ -57,10 +62,12 @@ public class MusicControls extends HorizontalGroup {
forward.addListener(new ChangeListener() { forward.addListener(new ChangeListener() {
@Override @Override
public void changed(ChangeEvent event, Actor actor) { public void changed(ChangeEvent event, Actor actor) {
boolean wasPlaying = sc.getCurrentMusicManager().isPlaying(); if (sc.getCurrentMusicManager() != null) {
sc.skip(); boolean wasPlaying = sc.getCurrentMusicManager().isPlaying();
if (wasPlaying) { sc.skip();
sc.play(); if (wasPlaying) {
sc.play();
}
} }
forward.setDisabled(true); forward.setDisabled(true);

View File

@ -46,8 +46,8 @@ public class Visualizer extends Widget implements Disposable {
public void setMM(MusicManager mm) { public void setMM(MusicManager mm) {
if (mm != null) { if (this.mm != null) {
mm.dispose(); this.mm.dispose();
} }
this.mm = mm; this.mm = mm;
mmSet = false; mmSet = false;

View File

@ -182,7 +182,7 @@ public class MusicSelectionPage extends Page implements Observer {
return currentlySelected.getAudioInfo(); return currentlySelected.getAudioInfo();
} }
public void refresh() { public void refreshUIList() {
musicTable.clear(); musicTable.clear();
selectables.clear(); selectables.clear();
musicInfoTable.clear(); musicInfoTable.clear();
@ -283,13 +283,11 @@ public class MusicSelectionPage extends Page implements Observer {
public void update(Observable o, Object arg) { public void update(Observable o, Object arg) {
if (o == mc) { if (o == mc) {
MusicManager mm = (MusicManager) arg; MusicManager mm = (MusicManager) arg;
selectSong(mm); selectMusicUI(mm);
} else if (o == mc.getMusicList()) {
refresh();
} }
} }
public void selectSong(MusicManager mm) { public void selectMusicUI(MusicManager mm) {
if (currentlySelected == null || mm.getMusicFile() != currentlySelected.getMusicFile()) { if (currentlySelected == null || mm.getMusicFile() != currentlySelected.getMusicFile()) {
for (int i = 0; i < selectables.size; i++) { for (int i = 0; i < selectables.size; i++) {
if (selectables.get(i).getMusicFile() == mm.getMusicFile()) { if (selectables.get(i).getMusicFile() == mm.getMusicFile()) {
@ -309,7 +307,6 @@ public class MusicSelectionPage extends Page implements Observer {
if (currentlySelected.getMusicFile() != mc.getCurrentMusicManager().getMusicFile()) { if (currentlySelected.getMusicFile() != mc.getCurrentMusicManager().getMusicFile()) {
int index = mc.getMusicList().getMusicList().indexOf(currentlySelected.getMusicFile(), true); int index = mc.getMusicList().getMusicList().indexOf(currentlySelected.getMusicFile(), true);
mc.setMusicByIndex(index); mc.setMusicByIndex(index);
mc.play();
} }
} }

View File

@ -92,7 +92,7 @@ public class OptionsPage extends Page {
musicSearchTimer -= delta; musicSearchTimer -= delta;
if (musicSearchTimer <= 0) { if (musicSearchTimer <= 0) {
sc.getMusicList().setSearchPath(directoryField.getText()); sc.getMusicList().setSearchPath(directoryField.getText());
sc.getMusicList().refresh(); sc.getMusicList().asynchRefresh();
songCount.setText("Songs: " + sc.getMusicList().getAmountOfMusic()); songCount.setText("Songs: " + sc.getMusicList().getAmountOfMusic());
} }
} }

View File

@ -1,98 +0,0 @@
package zero1hd.rhythmbullet.graphics.ui.windows;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.List;
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.Window;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.Array;
import zero1hd.rhythmbullet.audio.MusicManager;
import zero1hd.rhythmbullet.audio.MusicList;
import zero1hd.rhythmbullet.util.MiniEvents;
import zero1hd.rhythmbullet.util.MiniSender;
public class MusicSelector extends Window {
boolean confirmed;
boolean back;
FileHandle selectedMusic;
Array<String> fileNames;
private List<String> musicList;
private ScrollPane listScroller;
private MusicList songList;
public MiniSender miniSender;
public MusicSelector(String title, Skin skin, final String path, MusicList songList) {
super(title, skin, "tinted");
padTop(25f);
padLeft(5f);
padRight(5f);
this.songList = songList;
miniSender = new MiniSender();
setSize(Gdx.graphics.getWidth()*0.5f, Gdx.graphics.getHeight()*0.5f);
fileNames = new Array<>();
musicList = new List<String>(skin, "default");
TextButton confirmButton = new TextButton("confirm", skin, "window");
confirmButton.addListener(new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
confirmed = true;
selectedMusic = Gdx.files.absolute(path+System.getProperty("file.separator")+musicList.getSelected());
miniSender.send(MiniEvents.MUSIC_SELECTED);
}
});
add(confirmButton);
TextButton regenMap = new TextButton("regen map", skin, "window");
regenMap.addListener(new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
miniSender.send(MiniEvents.MUSIC_DATA_CLEANED);
}
});
add(regenMap);
row();
listScroller = new ScrollPane(musicList, skin);
listScroller.setScrollingDisabled(true, false);
add(listScroller).colspan(2).expand().fill().prefWidth(getWidth()-5);
}
public void refresh() {
songList.refresh();
musicList.setItems(songList.getMusicList());
}
public boolean isConfirmed() {
boolean isConfirmed = confirmed;
confirmed = false;
return isConfirmed;
}
public boolean isBack() {
boolean isBack = back;
back = false;
return isBack;
}
public MusicManager getSelectedMusic() {
if (selectedMusic != null) {
return songList.getAudioData(selectedMusic);
} else {
return null;
}
}
}

View File

@ -65,12 +65,10 @@ public class MainMenu extends ScreenAdapter implements TransitionAdapter {
MusicList musicList = new MusicList(); MusicList musicList = new MusicList();
musicList.setSearchPath(core.getPrefs().getString("music dir")); musicList.setSearchPath(core.getPrefs().getString("music dir"));
musicList.refresh(); musicList.asynchRefresh();
mlc = new MusicListController(musicList, core.getPrefs()); mlc = new MusicListController(musicList, core.getPrefs());
mlc.setAutoPlay(true); mlc.setAutoPlay(true);
mlc.setShuffle(true); mlc.setShuffle(true);
mlc.shuffle(true);
postTransition(); postTransition();
} }
@ -136,9 +134,6 @@ public class MainMenu extends ScreenAdapter implements TransitionAdapter {
mlc.addObserver(mainPage); mlc.addObserver(mainPage);
mlc.addObserver(musicSelectionPage); mlc.addObserver(musicSelectionPage);
mlc.getMusicList().addObserver(musicSelectionPage); mlc.getMusicList().addObserver(musicSelectionPage);
musicSelectionPage.refresh();
mainPage.updateVisualsForDifferentSong(mlc.getCurrentMusicManager());
musicSelectionPage.selectSong(mlc.getCurrentMusicManager());
} }
public void attemptLoadShaders() { public void attemptLoadShaders() {
if (core.getPrefs().getBoolean("glow shader", true)) { if (core.getPrefs().getBoolean("glow shader", true)) {
@ -216,7 +211,7 @@ public class MainMenu extends ScreenAdapter implements TransitionAdapter {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(delta); stage.act(delta);
if (blurlvl > 0) { if (blurlvl > 0) {
//Begin drawing a normal version of screen // Begin drawing a normal version of screen
normalBuffer.begin(); normalBuffer.begin();
stage.getViewport().apply(); stage.getViewport().apply();
Gdx.gl.glClearColor(0.22f, 0f, 0f, 1f); Gdx.gl.glClearColor(0.22f, 0f, 0f, 1f);
@ -224,7 +219,7 @@ public class MainMenu extends ScreenAdapter implements TransitionAdapter {
stage.draw(); stage.draw();
normalBuffer.end(); normalBuffer.end();
//BEGINNING NORMAL SCREEN RENDER // BEGINNING NORMAL SCREEN RENDER
screenViewport.apply(); screenViewport.apply();
// Begin light filtering // Begin light filtering
@ -294,7 +289,6 @@ public class MainMenu extends ScreenAdapter implements TransitionAdapter {
@Override @Override
public void show() { public void show() {
Gdx.input.setInputProcessor(stage); Gdx.input.setInputProcessor(stage);
mlc.play();
calcLerpAlpha(Gdx.graphics.getWidth()); calcLerpAlpha(Gdx.graphics.getWidth());
super.show(); super.show();
} }