From 5ce0e6416e9e821be69219cc8a949c00e2cb462c Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Fri, 24 Dec 2021 21:05:01 +0100 Subject: [PATCH] Fix animation freeze when loading music files (#609) * Implement async music loading * Simplify music filename parsing and fix "missing" on streams Co-authored-by: oldmud0 --- include/aomusicplayer.h | 6 +++++- include/courtroom.h | 4 ++++ src/aomusicplayer.cpp | 39 +++++++++++++++++++++++++++++----- src/courtroom.cpp | 47 ++++++++++++++++++----------------------- 4 files changed, 64 insertions(+), 32 deletions(-) diff --git a/include/aomusicplayer.h b/include/aomusicplayer.h index f899b9a..7c9bfb3 100644 --- a/include/aomusicplayer.h +++ b/include/aomusicplayer.h @@ -10,6 +10,8 @@ #include #include #include +#include +#include class AOMusicPlayer { public: @@ -24,8 +26,10 @@ public: int loop_start[4] = {0, 0, 0, 0}; int loop_end[4] = {0, 0, 0, 0}; + QFutureWatcher music_watcher; + public slots: - int play(QString p_song, int channel = 0, bool loop = false, + QString play(QString p_song, int channel = 0, bool loop = false, int effect_flags = 0); void stop(int channel = 0); diff --git a/include/courtroom.h b/include/courtroom.h index 4bc8624..9df3b90 100644 --- a/include/courtroom.h +++ b/include/courtroom.h @@ -57,6 +57,8 @@ #include #include +#include + #include #include @@ -814,6 +816,8 @@ public slots: bool steno); void on_reload_theme_clicked(); + void update_ui_music_name(); + private slots: void start_chat_ticking(); void play_sfx(); diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index d0d9563..16d6df7 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -13,12 +13,13 @@ AOMusicPlayer::~AOMusicPlayer() } } -int AOMusicPlayer::play(QString p_song, int channel, bool loop, +QString AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_flags) { + QFuture invoking_future = music_watcher.future(); channel = channel % m_channelmax; if (channel < 0) // wtf? - return BASS_ERROR_NOCHAN; + return "[ERROR] Invalid Channel"; QString f_path = ao_app->get_real_path(ao_app->get_music_path(p_song)); unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | @@ -43,6 +44,14 @@ int AOMusicPlayer::play(QString p_song, int channel, bool loop, newstream = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, flags); } + int error_code = BASS_ErrorGetCode(); + + if (invoking_future.isCanceled() && channel == 0) { + // Target future has changed. This stream has become irrelevant. + // So even if the stream manages to finish after the latest one, we don't run + // into order issues. + return QString(); + } if (ao_app->get_audio_output_device() != "default") BASS_ChannelSetDevice(m_stream_list[channel], BASS_GetDevice()); @@ -109,7 +118,7 @@ int AOMusicPlayer::play(QString p_song, int channel, bool loop, BASS_ChannelStop(m_stream_list[channel]); m_stream_list[channel] = newstream; - BASS_ChannelPlay(m_stream_list[channel], false); + BASS_ChannelPlay(newstream, false); if (effect_flags & FADE_IN) { // Fade in our sample BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0); @@ -120,12 +129,32 @@ int AOMusicPlayer::play(QString p_song, int channel, bool loop, else this->set_volume(m_volume[channel], channel); - BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_DEV_FAIL, 0, + BASS_ChannelSetSync(newstream, BASS_SYNC_DEV_FAIL, 0, ao_app->BASSreset, 0); this->set_looping(loop, channel); // Have to do this here due to any // crossfading-related changes, etc. - return BASS_ErrorGetCode(); + + bool is_stop = (p_song == "~stop.mp3"); + QString p_song_clear = QUrl(p_song).fileName(); + p_song_clear = p_song_clear.left(p_song_clear.lastIndexOf('.')); + + if (is_stop) { + return QObject::tr("None"); + } + + if (error_code == BASS_ERROR_HANDLE) { // Cheap hack to see if file missing + return QObject::tr("[MISSING] %1").arg(p_song_clear); + } + + if (p_song.startsWith("http") && channel == 0) { + return QObject::tr("[STREAM] %1").arg(p_song_clear); + } + + if (channel == 0) + return p_song_clear; + + return ""; } void AOMusicPlayer::stop(int channel) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 3eda163..a9f2da6 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -27,6 +27,8 @@ Courtroom::Courtroom(AOApplication *p_ao_app) : QMainWindow() music_player = new AOMusicPlayer(this, ao_app); music_player->set_volume(0); + connect(&music_player->music_watcher, &QFutureWatcher::finished, + this, &Courtroom::update_ui_music_name, Qt::QueuedConnection); sfx_player = new AOSfxPlayer(this, ao_app); sfx_player->set_volume(0); @@ -3807,13 +3809,8 @@ void Courtroom::handle_song(QStringList *p_contents) int effect_flags = 0; // No effects by default - vanilla functionality QString f_song = f_contents.at(0); - QString f_song_clear = f_song.left(f_song.lastIndexOf(".")); - if (f_song.startsWith("http")) { - QByteArray f_song_bytearray = f_song.toUtf8(); - QString f_song_decoded = QUrl::fromPercentEncoding(f_song_bytearray); - f_song_clear = f_song_decoded.left(f_song_decoded.lastIndexOf(".")); - } - f_song_clear = f_song_clear.right(f_song_clear.length() - (f_song_clear.lastIndexOf("/") + 1)); + QString f_song_clear = QUrl(f_song).fileName(); + f_song_clear = f_song_clear.left(f_song_clear.lastIndexOf('.')); int n_char = f_contents.at(1).toInt(&ok); if (!ok) @@ -3862,27 +3859,25 @@ void Courtroom::handle_song(QStringList *p_contents) } } - int error_code = music_player->play(f_song, channel, looping, effect_flags); - - if (is_stop) { - ui_music_name->setText(tr("None")); - return; + QFuture future = QtConcurrent::run(music_player, &AOMusicPlayer::play, f_song, channel, + looping, effect_flags); + if (channel == 0) { + // Current song UI only displays the song playing, not other channels. + // Any other music playing is irrelevant. + if (music_player->music_watcher.isRunning()) { + music_player->music_watcher.cancel(); + } + music_player->music_watcher.setFuture(future); + ui_music_name->setText(tr("[LOADING] %1").arg(f_song_clear)); } +} - if (error_code == BASS_ERROR_HANDLE) { // Cheap hack to see if file missing - ui_music_name->setText(tr("[MISSING] %1").arg(f_song_clear)); - return; - } - - if (f_song.startsWith("http") && channel == 0) { - ui_music_name->setText(tr("[STREAM] %1").arg(f_song_clear)); - return; - } - - if (channel == 0){ - ui_music_name->setText(f_song_clear); - return; - } +void Courtroom::update_ui_music_name() +{ + QString result = music_player->music_watcher.result(); + if (result.isEmpty()) + return; + ui_music_name->setText(result); } void Courtroom::handle_wtce(QString p_wtce, int variant)