Closed jeltedeproft closed 11 months ago
Hmm that's a tough one. The only thing I can think of that makes a difference between normal and debug mode is time. Like more time has passed until that line is run. If you could provide a minimal example project where the issue is reproducable, that would be great but isn't necessary of course. I'll dig into the issue tomorrow.
Thanks for reporting!
I wasn't able to reproduce the issue so far. I was just trying to break the system in any way I could think of. Though, I might have missed the case that leads to your issue.
Are you by any chance calling
case MUSIC_CHANGE_THEME:
provider.setTheme(audioData.getTheme());
jukeBox.softStopAndResume(Interpolation.linear, 2f);
break;
or jukebox.update()
on different threads?
Could also be something simple on your side like accidently calling jukebox.stop()
after jukebox.softStopAndResume()
, streamed sounds could play in the background while the main thread is halted by the debugger.
I'd recommend to jukebox.addObserver(...)
and log/print those events for debugging purposes. The debugger could lead to false results here as so much is based on time (fade in/out durations etc.).
Unfortunately, the jukebox events are fired in a kinda random order within a single frame. Not a big deal normally, but in this case it could cause some confusion.
I've quickly written something that should spit out all events in proper order.
implementation 'com.github.Hangman:TuningFork:proper_jukebox_events-SNAPSHOT'
which also includes a quick test of the ThemePlayListProvider
If you prefer a chat over slow issue conversations, feel free to hit me up on discord => "mrwinterbottom".
Thank you so much for jumping on this issue so fast. I'm gonna investigate a bit more with your suggestions and I'll update this thread with my findings. (bit bussy atm)
Your first 2 suggestions doesn't seem to apply to me. They seem to be called from the same thread. I don't seem to be calling stop() after softStopAndResume().
How am I suposed to be using these events? Do I import your new version and then just run my game and check the logs, or?
hmm ok so i added the observer and logged all events, I only have this in the log
JukeBoxObserverLogger: onJukeBoxStart :
JukeBoxObserverLogger: onPlayListStart first song : mainMenu
JukeBoxObserverLogger: onSongStart : mainMenu
When it is suposed to change playlist, nothing is logged
I do have some of my own code that is being logged, so my code is being executed
DEBUG: [d.e.c.s.ScreenManager ]: Screen 'play' was pushed, using the transition 'luminance'
MusicManager: changed to theme : 0
MusicManager: jukeBox current song : de.pottgames.tuningfork.jukebox.song.Song@c7ba306
MusicManager: before update
That could mean there's no corresponding PlayList
for the chosen theme.
If I do something like:
provider.add(playList0, 0);
// provider.add(playList1, 1); <- missing code
provider.setTheme(0);
JukeBox jukeBox = new JukeBox(provider);
jukeBox.play();
provider.setTheme(1);
jukeBox.softStopAndResume(Interpolation.linear, 2f);
I get the same behavior. I will add some some checks and warning logs for those cases after christmas.
Let's hope it's just this. If not, I'll be available again after the holidays. Merry Christmas
hmm that doesn't seem to be the case.
When I debug the themes seem to be set correctly
[0=de.pottgames.tuningfork.jukebox.playlist.PlayList@73194df, 3=de.pottgames.tuningfork.jukebox.playlist.PlayList@3a4621bd, 1=de.pottgames.tuningfork.jukebox.playlist.PlayList@6eb2384f, 4=de.pottgames.tuningfork.jukebox.playlist.PlayList@31dadd46, 2=de.pottgames.tuningfork.jukebox.playlist.PlayList@3c9c0d96]
Also my own logging says im adding the right themes
MusicManager: adding to provider playlist : de.pottgames.tuningfork.jukebox.playlist.PlayList@73194df
MusicManager: adding to provider theme : 0
MusicManager: adding to provider playlist : de.pottgames.tuningfork.jukebox.playlist.PlayList@6eb2384f
MusicManager: adding to provider theme : 1
MusicManager: adding to provider playlist : de.pottgames.tuningfork.jukebox.playlist.PlayList@3c9c0d96
MusicManager: adding to provider theme : 2
MusicManager: adding to provider playlist : de.pottgames.tuningfork.jukebox.playlist.PlayList@3a4621bd
MusicManager: adding to provider theme : 3
MusicManager: adding to provider playlist : de.pottgames.tuningfork.jukebox.playlist.PlayList@31dadd46
MusicManager: adding to provider theme : 4
And I can see in the code the theme is 0 and its updating it with 1
Okido, Merry christmas, enjoy your holidays
here is also my complete musicManager class, maybe you spot something off?
public class MusicManager implements Disposable, MusicManagerInterface {
private static final String TAG = MusicManager.class.getSimpleName();
private static MusicManagerInterface instance = null;
private final Audio audio;
private ThemePlayListProvider provider;
private JukeBox jukeBox;
private final Map<Integer, AudioData> audioEnumToAudioData = new HashMap<>();
private final HashMap<String, Array<BufferedSoundSource>> loadedSounds = new HashMap<>();
private MusicManager() {
audio = Audio.init(new AudioConfig().setLogger((MultiFileLogger) Gdx.app.getApplicationLogger()));
loadSounds();
jukeBox = loadAndInitJukeBox();
jukeBox.addObserver(new JukeBoxObserverLogger());
jukeBox.play();
jukeBox.update();
Gdx.app.debug(TAG, "jukeBox starting song : " + jukeBox.getCurrentSong().getMeta().getTitle());
}
private void loadSounds() {
loadAudio(AudioEnum::isSound, (fullFilePath, audioData) -> AssetManagerUtility.loadSoundBufferAsset(fullFilePath));
}
private void loadAudio(Predicate<AudioEnum> filter, BiConsumer<String, AudioData> loader) {
for (AudioEnum audioEnum : AudioEnum.values()) {
if (filter.test(audioEnum)) {
AudioData audioData = getAudioData(audioEnum);
audioData.getAudioFileName().forEach(fullFilePath -> loader.accept(fullFilePath, audioData));
}
}
}
private AudioData getAudioData(AudioEnum event) {
return audioEnumToAudioData.computeIfAbsent(event.ordinal(), ordinal -> AudioFileReader.getAudioData().get(ordinal));
}
private JukeBox loadAndInitJukeBox() {
Map<MusicTheme, PlayList> playlistsPerTheme = new EnumMap<>(MusicTheme.class);
for (MusicTheme theme : MusicTheme.values()) {
PlayList playlist = new PlayList();
playlist.setLooping(true);
playlist.setShuffleAfterPlaytrough(true);
playlistsPerTheme.put(theme, playlist);
}
loadAudio(AudioEnum::isPlaylist, (fullFilePath, audioData) -> {
StreamedSoundSource music = new StreamedSoundSource(Gdx.files.internal(fullFilePath));
SongMeta meta = new SongMeta().setTitle(audioData.getName());
SongSettings settings = SongSettings.linear(audioData.getVolume(), Constants.MUSIC_FADE_IN_DURATION, Constants.MUSIC_FADE_OUT_DURATION);
Song song = new Song(music, settings, meta);
playlistsPerTheme.get(MusicTheme.values()[audioData.getTheme()]).addSong(song);
});
playlistsPerTheme.values().forEach(PlayList::shuffle);
provider = new ThemePlayListProvider();
for (Entry<MusicTheme, PlayList> entry : playlistsPerTheme.entrySet()) {
Gdx.app.debug(TAG, "adding to provider playlist : " + entry.getValue());
Gdx.app.debug(TAG, "adding to provider theme : " + entry.getKey().ordinal());
provider.add(entry.getValue(), entry.getKey().ordinal());
}
provider.setTheme(MusicTheme.MAIN_MENU.ordinal());
return new JukeBox(provider);
}
@Override
public void update(float delta) {
jukeBox.update();
}
@Override
public void sendCommand(AudioCommand command, AudioEnum event) {
final AudioData audioData = getAudioData(event);
final float volume = audioData.getVolume();
switch (command) {
case SOUND_PLAY_LOOP:
playLoopedSound(audioData.getRandomAudioFileName(), volume, null);
break;
case SOUND_PLAY_ONCE:
playAndForget(audioData.getRandomAudioFileName(), volume, null);
break;
case SOUND_STOP:
stopAllSounds(audioData.getAudioFileName());
break;
case MUSIC_CHANGE_THEME:
provider.setTheme(audioData.getTheme());
jukeBox.softStopAndResume(Interpolation.linear, 2f);
Gdx.app.debug(TAG, "changed to theme : " + audioData.getTheme());
Gdx.app.debug(TAG, "jukeBox current song : " + jukeBox.getCurrentSong());
break;
case MUSIC_PAUSE:
jukeBox.pause();
break;
case MUSIC_STOP:
jukeBox.stop();
break;
default:
break;
}
}
private BufferedSoundSource playLoopedSound(String fullFilePath, float volume, CellPosition pos) {
BufferedSoundSource sound = createBufferedSound(fullFilePath, volume);
if (sound != null) {
if (pos != null) {
sound.setPosition(pos.x, pos.y, 0);
}
sound.play();
}
return sound;
}
private void playAndForget(String fullFilePath, float volume, CellPosition pos) {
if (AssetManagerUtility.isAssetLoaded(fullFilePath)) {
SoundBuffer soundBuffer = AssetManagerUtility.getSoundBufferAsset(fullFilePath);
if (pos != null) {
soundBuffer.play3D(volume, new Vector3(pos.x, pos.y, 0));
} else {
soundBuffer.play(volume);
}
}
}
private void stopAllSounds(List<String> audioFileNames) {
audioFileNames.forEach(name -> {
final Array<BufferedSoundSource> sounds = loadedSounds.get(name);
if (sounds != null && sounds.size > 0) {
sounds.get(0).stop();
sounds.removeIndex(0);
}
});
}
private BufferedSoundSource createBufferedSound(String fullFilePath, float volume) {
loadedSounds.computeIfAbsent(fullFilePath, s -> new Array<>());
if (AssetManagerUtility.isAssetLoaded(fullFilePath)) {
SoundBuffer soundBuffer = AssetManagerUtility.getSoundBufferAsset(fullFilePath);
BufferedSoundSource bufferedSound = audio.obtainSource(soundBuffer);
bufferedSound.setVolume(volume);
bufferedSound.setLooping(true);
loadedSounds.get(fullFilePath).add(bufferedSound);
return bufferedSound;
}
Gdx.app.error(TAG, "Sound not loaded", null);
return null;
}
public static MusicManagerInterface getInstance() {
if (instance == null) {
instance = new MusicManager();
}
return instance;
}
public static void setInstance(MusicManagerInterface newInstance) {
instance = newInstance;
}
@Override
public void dispose() {
loadedSounds.values().forEach(array -> array.forEach(BufferedSoundSource::free));
audio.dispose();
}
}
What are the values for Constants.MUSIC_FADE_IN_DURATION
and Constants.MUSIC_FADE_OUT_DURATION
?
When it is suposed to change playlist, nothing is logged
It first fades out the current song, during which no logs are generated. The interesting part starts after waiting for Constants.MUSIC_FADE_OUT_DURATION
seconds when the PlayList change should occur. Does the jukebox
softStopAndResume
?If it's the former, I can trigger this behavior with either no playlist for the theme or an empty playlist for the theme.
If it's the latter, I don't really know what happens (unless Constants.MUSIC_FADE_OUT_DURATION
is very high) and I can't reproduce this behavior. In this case a MRE would be very helpful.
Gdx.app.debug(TAG, "jukeBox current song : " + jukeBox.getCurrentSong());
will probably always print mainMenu
at that point because the song isn't changed until the fade-out is complete, so that's expected.
JukeBoxObserverLogger: onJukeBoxStart :
JukeBoxObserverLogger: onPlayListStart first song : mainMenu
JukeBoxObserverLogger: onSongStart : mainMenu
If you let it run longer, what are the next few jukebox logs after those 3 lines?
omg I'm so dumb, my main game screen didn't call update() on the musicManager. I'm so sorry for wasting your time with this. Should have investigated a bit more before posting here
works perfectly now
Hey no worries, this is good news actually. Glad it works now!
I have the following code
When i play my game normally the song does not change. When I put a debug point here
Then the debugger stops there and at that line the music stops and it changes to another song. Do you have any explanation for this?