mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-06-02 04:36:57 -06:00
cellMusic: improve music list playback
This commit is contained in:
parent
9c719a5857
commit
059e70069d
@ -79,33 +79,38 @@ struct music_state
|
||||
music_state()
|
||||
{
|
||||
handler = Emu.GetCallbacks().get_music_handler();
|
||||
handler->set_status_callback([this](music_handler_base::player_status status)
|
||||
handler->set_event_status_callback([this](u32 status)
|
||||
{
|
||||
// TODO: disabled until I find a game that uses CELL_MUSIC_EVENT_STATUS_NOTIFICATION
|
||||
return;
|
||||
|
||||
if (!func)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s32 result = CELL_OK;
|
||||
|
||||
// Known to be used by NFS: Hot Pursuit
|
||||
sysutil_register_cb([this, state = status](ppu_thread& ppu) -> s32
|
||||
{
|
||||
cellMusic.notice("Sending status notification %d", state);
|
||||
func(ppu, CELL_MUSIC_EVENT_STATUS_NOTIFICATION, vm::addr_t(state), userData);
|
||||
return CELL_OK;
|
||||
});
|
||||
});
|
||||
handler->set_playback_status_callback([this](music_handler_base::player_status status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case music_handler_base::player_status::end_of_media:
|
||||
result = CELL_MUSIC_PLAYBACK_FINISHED;
|
||||
// Let's just play the next song for now
|
||||
if (current_selection_context.content_type == CELL_SEARCH_CONTENTTYPE_MUSICLIST && handler->get_state() == CELL_MUSIC_PB_STATUS_PLAY)
|
||||
{
|
||||
if (const error_code error = set_playback_command(CELL_MUSIC_PB_CMD_NEXT))
|
||||
{
|
||||
cellMusic.error("Failed to play next track. error=0x%x", +error);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
sysutil_register_cb([this, &result](ppu_thread& ppu) -> s32
|
||||
{
|
||||
cellMusic.notice("Sending status notification %d", result);
|
||||
func(ppu, CELL_MUSIC_EVENT_STATUS_NOTIFICATION, vm::addr_t(result), userData);
|
||||
return CELL_OK;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -287,6 +287,8 @@ u32 music_selection_context::step_track(bool next)
|
||||
return umax;
|
||||
}
|
||||
|
||||
const std::string last_track = ::at32(playlist, current_track);
|
||||
|
||||
switch (repeat_mode)
|
||||
{
|
||||
case CELL_SEARCH_REPEATMODE_NONE:
|
||||
@ -365,6 +367,12 @@ u32 music_selection_context::step_track(bool next)
|
||||
std::random_device rd;
|
||||
auto engine = std::default_random_engine{rd()};
|
||||
std::shuffle(std::begin(playlist), std::end(playlist), engine);
|
||||
|
||||
// Don't play the same track twice
|
||||
if (last_track == ::at32(playlist, current_track))
|
||||
{
|
||||
current_track = (current_track + 1) % playlist.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1711,12 +1711,6 @@ error_code cellSearchGetMusicSelectionContext(CellSearchId searchId, vm::cptr<Ce
|
||||
auto content = std::find_if(searchObject->content_ids.begin(), searchObject->content_ids.end(), [&content_hash](const content_id_type& cid){ return cid.first == content_hash; });
|
||||
if (content != searchObject->content_ids.cend() && content->second)
|
||||
{
|
||||
// Check if the type of the found content is correct
|
||||
if (content->second->type != CELL_SEARCH_CONTENTTYPE_MUSIC)
|
||||
{
|
||||
return { CELL_SEARCH_ERROR_INVALID_CONTENTTYPE, "Type: %d, Expected: CELL_SEARCH_CONTENTTYPE_MUSIC"};
|
||||
}
|
||||
|
||||
// Check if the type of the found content matches our search content type
|
||||
if (content->second->type != first_content->type)
|
||||
{
|
||||
@ -1724,8 +1718,36 @@ error_code cellSearchGetMusicSelectionContext(CellSearchId searchId, vm::cptr<Ce
|
||||
}
|
||||
|
||||
// Use the found content
|
||||
context.playlist.push_back(content->second->infoPath.contentPath);
|
||||
cellSearch.notice("cellSearchGetMusicSelectionContext(): Hash=%08X, Assigning found track: Type=0x%x, Path=%s", content_hash, +content->second->type, context.playlist.back());
|
||||
if (content->second->type == CELL_SEARCH_CONTENTTYPE_MUSICLIST)
|
||||
{
|
||||
const std::string path = content->second->infoPath.contentPath;
|
||||
const std::string vfs_path = vfs::get(path);
|
||||
if (!fs::is_dir(vfs_path))
|
||||
{
|
||||
return { CELL_SEARCH_ERROR_CONTENT_NOT_FOUND, "Not a directory: Path='%s'", vfs_path };
|
||||
}
|
||||
|
||||
for (auto&& dir_entry : fs::dir{vfs_path})
|
||||
{
|
||||
if (dir_entry.name == "." || dir_entry.name == "..")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string track = path + "/" + dir_entry.name;
|
||||
cellSearch.notice("cellSearchGetMusicSelectionContext(): Hash=%08X, Assigning found track: Type=0x%x, Path='%s'", content_hash, +content->second->type, track);
|
||||
context.playlist.push_back(std::move(track));
|
||||
}
|
||||
}
|
||||
else if (content->second->type == CELL_SEARCH_CONTENTTYPE_MUSIC)
|
||||
{
|
||||
context.playlist.push_back(content->second->infoPath.contentPath);
|
||||
cellSearch.notice("cellSearchGetMusicSelectionContext(): Hash=%08X, Assigning found track: Type=0x%x, Path='%s'", content_hash, +content->second->type, context.playlist.back());
|
||||
}
|
||||
else
|
||||
{
|
||||
return { CELL_SEARCH_ERROR_INVALID_CONTENTTYPE, "Type: %d, Expected: CELL_SEARCH_CONTENTTYPE_MUSIC or CELL_SEARCH_CONTENTTYPE_MUSICLIST", +content->second->type };
|
||||
}
|
||||
}
|
||||
else if (first_content->type == CELL_SEARCH_CONTENTTYPE_MUSICLIST)
|
||||
{
|
||||
@ -1738,14 +1760,14 @@ error_code cellSearchGetMusicSelectionContext(CellSearchId searchId, vm::cptr<Ce
|
||||
// TODO: whole playlist
|
||||
shared_ptr<search_content_t> content = get_random_content();
|
||||
context.playlist.push_back(content->infoPath.contentPath);
|
||||
cellSearch.notice("cellSearchGetMusicSelectionContext(): Hash=%08X, Assigning random track: Type=0x%x, Path=%s", content_hash, +content->type, context.playlist.back());
|
||||
cellSearch.notice("cellSearchGetMusicSelectionContext(): Hash=%08X, Assigning random track: Type=0x%x, Path='%s'", content_hash, +content->type, context.playlist.back());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Select the first track by default
|
||||
// TODO: whole playlist
|
||||
context.playlist.push_back(first_content->infoPath.contentPath);
|
||||
cellSearch.notice("cellSearchGetMusicSelectionContext(): Hash=%08X, Assigning first track: Type=0x%x, Path=%s", content_hash, +first_content->type, context.playlist.back());
|
||||
cellSearch.notice("cellSearchGetMusicSelectionContext(): Hash=%08X, Assigning first track: Type=0x%x, Path='%s'", content_hash, +first_content->type, context.playlist.back());
|
||||
}
|
||||
}
|
||||
else if (first_content->type == CELL_SEARCH_CONTENTTYPE_MUSICLIST)
|
||||
@ -1759,14 +1781,14 @@ error_code cellSearchGetMusicSelectionContext(CellSearchId searchId, vm::cptr<Ce
|
||||
// TODO: whole playlist
|
||||
shared_ptr<search_content_t> content = get_random_content();
|
||||
context.playlist.push_back(content->infoPath.contentPath);
|
||||
cellSearch.notice("cellSearchGetMusicSelectionContext(): Assigning random track: Type=0x%x, Path=%s", +content->type, context.playlist.back());
|
||||
cellSearch.notice("cellSearchGetMusicSelectionContext(): Assigning random track: Type=0x%x, Path='%s'", +content->type, context.playlist.back());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Select the first track by default
|
||||
// TODO: whole playlist
|
||||
context.playlist.push_back(first_content->infoPath.contentPath);
|
||||
cellSearch.notice("cellSearchGetMusicSelectionContext(): Assigning first track: Type=0x%x, Path=%s", +first_content->type, context.playlist.back());
|
||||
cellSearch.notice("cellSearchGetMusicSelectionContext(): Assigning first track: Type=0x%x, Path='%s'", +first_content->type, context.playlist.back());
|
||||
}
|
||||
|
||||
context.content_type = first_content->type;
|
||||
|
||||
@ -7,11 +7,11 @@ class null_music_handler final : public music_handler_base
|
||||
public:
|
||||
null_music_handler() : music_handler_base() {}
|
||||
|
||||
void stop() override { m_state = 0; } // CELL_MUSIC_PB_STATUS_STOP
|
||||
void pause() override { m_state = 2; } // CELL_MUSIC_PB_STATUS_PAUSE
|
||||
void play(const std::string& /*path*/) override { m_state = 1; } // CELL_MUSIC_PB_STATUS_PLAY
|
||||
void fast_forward(const std::string& /*path*/) override { m_state = 3; } // CELL_MUSIC_PB_STATUS_FASTFORWARD
|
||||
void fast_reverse(const std::string& /*path*/) override { m_state = 4; } // CELL_MUSIC_PB_STATUS_FASTREVERSE
|
||||
void stop() override { set_state(0); } // CELL_MUSIC_PB_STATUS_STOP
|
||||
void pause() override { set_state(2); } // CELL_MUSIC_PB_STATUS_PAUSE
|
||||
void play(const std::string& /*path*/) override { set_state(1); } // CELL_MUSIC_PB_STATUS_PLAY
|
||||
void fast_forward(const std::string& /*path*/) override { set_state(3); } // CELL_MUSIC_PB_STATUS_FASTFORWARD
|
||||
void fast_reverse(const std::string& /*path*/) override { set_state(4); } // CELL_MUSIC_PB_STATUS_FASTREVERSE
|
||||
void set_volume(f32 volume) override { m_volume = volume; }
|
||||
f32 get_volume() const override { return m_volume; }
|
||||
|
||||
|
||||
@ -21,17 +21,35 @@ public:
|
||||
virtual void set_volume(f32 volume) = 0;
|
||||
virtual f32 get_volume() const = 0;
|
||||
|
||||
s32 get_state() const
|
||||
void set_state(u32 state)
|
||||
{
|
||||
m_state = state;
|
||||
|
||||
if (m_event_status_callback)
|
||||
{
|
||||
m_event_status_callback(state);
|
||||
}
|
||||
}
|
||||
|
||||
u32 get_state() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
void set_status_callback(std::function<void(player_status)> status_callback)
|
||||
void set_event_status_callback(std::function<void(u32)> status_callback)
|
||||
{
|
||||
m_status_callback = std::move(status_callback);
|
||||
m_event_status_callback = std::move(status_callback);
|
||||
}
|
||||
|
||||
void set_playback_status_callback(std::function<void(player_status)> status_callback)
|
||||
{
|
||||
m_playback_status_callback = std::move(status_callback);
|
||||
}
|
||||
|
||||
private:
|
||||
atomic_t<u32> m_state{0};
|
||||
std::function<void(u32)> m_event_status_callback;
|
||||
|
||||
protected:
|
||||
atomic_t<s32> m_state{0};
|
||||
std::function<void(player_status status)> m_status_callback;
|
||||
std::function<void(player_status)> m_playback_status_callback;
|
||||
};
|
||||
|
||||
@ -97,7 +97,7 @@ void qt_music_handler::stop()
|
||||
m_media_player->stop();
|
||||
});
|
||||
|
||||
m_state = CELL_MUSIC_PB_STATUS_STOP;
|
||||
set_state(CELL_MUSIC_PB_STATUS_STOP);
|
||||
}
|
||||
|
||||
void qt_music_handler::pause()
|
||||
@ -110,7 +110,7 @@ void qt_music_handler::pause()
|
||||
m_media_player->pause();
|
||||
});
|
||||
|
||||
m_state = CELL_MUSIC_PB_STATUS_PAUSE;
|
||||
set_state(CELL_MUSIC_PB_STATUS_PAUSE);
|
||||
}
|
||||
|
||||
void qt_music_handler::play(const std::string& path)
|
||||
@ -135,7 +135,7 @@ void qt_music_handler::play(const std::string& path)
|
||||
m_media_player->play();
|
||||
});
|
||||
|
||||
m_state = CELL_MUSIC_PB_STATUS_PLAY;
|
||||
set_state(CELL_MUSIC_PB_STATUS_PLAY);
|
||||
}
|
||||
|
||||
void qt_music_handler::fast_forward(const std::string& path)
|
||||
@ -160,7 +160,7 @@ void qt_music_handler::fast_forward(const std::string& path)
|
||||
m_media_player->play();
|
||||
});
|
||||
|
||||
m_state = CELL_MUSIC_PB_STATUS_FASTFORWARD;
|
||||
set_state(CELL_MUSIC_PB_STATUS_FASTFORWARD);
|
||||
}
|
||||
|
||||
void qt_music_handler::fast_reverse(const std::string& path)
|
||||
@ -185,7 +185,7 @@ void qt_music_handler::fast_reverse(const std::string& path)
|
||||
m_media_player->play();
|
||||
});
|
||||
|
||||
m_state = CELL_MUSIC_PB_STATUS_FASTREVERSE;
|
||||
set_state(CELL_MUSIC_PB_STATUS_FASTREVERSE);
|
||||
}
|
||||
|
||||
void qt_music_handler::set_volume(f32 volume)
|
||||
@ -218,7 +218,7 @@ void qt_music_handler::handle_media_status(QMediaPlayer::MediaStatus status)
|
||||
{
|
||||
music_log.notice("New media status: %s (status=%d)", status, static_cast<int>(status));
|
||||
|
||||
if (!m_status_callback)
|
||||
if (!m_playback_status_callback)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -234,7 +234,7 @@ void qt_music_handler::handle_media_status(QMediaPlayer::MediaStatus status)
|
||||
case QMediaPlayer::MediaStatus::InvalidMedia:
|
||||
break;
|
||||
case QMediaPlayer::MediaStatus::EndOfMedia:
|
||||
m_status_callback(player_status::end_of_media);
|
||||
m_playback_status_callback(player_status::end_of_media);
|
||||
break;
|
||||
default:
|
||||
music_log.error("Ignoring unknown status %d", static_cast<int>(status));
|
||||
|
||||
@ -720,7 +720,8 @@ namespace utils
|
||||
{
|
||||
// Shuffle once if necessary
|
||||
media_log.notice("audio_decoder: shuffling initial playlist...");
|
||||
auto engine = std::default_random_engine{};
|
||||
std::random_device rd;
|
||||
auto engine = std::default_random_engine{rd()};
|
||||
std::shuffle(std::begin(m_context.playlist), std::end(m_context.playlist), engine);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user