From dc561e4df578c903087f9bdf56ff61d9ef9f2a93 Mon Sep 17 00:00:00 2001 From: Adrian <78108584+AdrianCassar@users.noreply.github.com> Date: Tue, 21 Apr 2026 18:40:16 +0100 Subject: [PATCH] [XMP] Fixed XMP Overriding Fixed cutscene audio in 58411446 Co-Authored-By: The-Little-Wolf <116989599+the-little-wolf@users.noreply.github.com> --- src/xenia/apu/audio_media_player.h | 32 +++-- src/xenia/kernel/xam/apps/xmp_app.cc | 181 +++++++++++++++++---------- src/xenia/kernel/xam/apps/xmp_app.h | 96 ++++++++------ 3 files changed, 191 insertions(+), 118 deletions(-) diff --git a/src/xenia/apu/audio_media_player.h b/src/xenia/apu/audio_media_player.h index 293b7f85a..86f183883 100644 --- a/src/xenia/apu/audio_media_player.h +++ b/src/xenia/apu/audio_media_player.h @@ -68,20 +68,28 @@ class AudioMediaPlayer { } XmpApp::PlaybackFlags GetPlaybackFlags() const { return playback_flags_; } - void SetPlaybackClient(XmpApp::PlaybackClient playback_client) { - if (playback_client == XmpApp::PlaybackClient::kSystem) { - return; - } + void SetXMPOverride(bool xmp_override) { xmp_override_ = xmp_override; } + bool IsXMPOverrideEnabled() const { return xmp_override_; } - playback_client_ = playback_client; - } - - XmpApp::PlaybackClient GetPlaybackClient() const { return playback_client_; } uint32_t GetDashInItState() const { return dash_init_state; } + void SetXMPClient(XMP_CLIENT xmp_client) { xmp_client_ = xmp_client; } + + void SetPlaybackController(PlaybackController playback_controller) { + playback_controller_ = playback_controller; + } + + PlaybackController GetPlaybackController() const { + return playback_controller_; + } + + XMP_CLIENT GetXMPClient() const { return xmp_client_; } + bool IsTitleInPlaybackControl() const { - return playback_client_ == XmpApp::PlaybackClient::kTitle || - is_title_rendering_enabled_; + const bool game_control = xmp_client_ == XMP_CLIENT::Game && + playback_controller_ == PlaybackController::Game; + + return game_control || xmp_override_ || is_title_rendering_enabled_; } void SetCaptureCallback(uint32_t callback, uint32_t context, @@ -102,10 +110,12 @@ class AudioMediaPlayer { std::span LoadSongToMemory(); XmpApp::State state_ = XmpApp::State::kIdle; - XmpApp::PlaybackClient playback_client_ = XmpApp::PlaybackClient::kSystem; + bool xmp_override_ = false; XmpApp::PlaybackMode playback_mode_ = XmpApp::PlaybackMode::kInOrder; XmpApp::RepeatMode repeat_mode_ = XmpApp::RepeatMode::kPlaylist; XmpApp::PlaybackFlags playback_flags_ = XmpApp::PlaybackFlags::kDefault; + PlaybackController playback_controller_ = PlaybackController::Game; + XMP_CLIENT xmp_client_ = XMP_CLIENT::Game; std::atomic volume_ = 0.0f; uint32_t dash_init_state = 0; diff --git a/src/xenia/kernel/xam/apps/xmp_app.cc b/src/xenia/kernel/xam/apps/xmp_app.cc index 0d95e0927..7fe79e88b 100644 --- a/src/xenia/kernel/xam/apps/xmp_app.cc +++ b/src/xenia/kernel/xam/apps/xmp_app.cc @@ -76,7 +76,7 @@ X_HRESULT XmpApp::XMPCreateTitlePlaylist( memory_->TranslateVirtual(song_descriptor[i].genre_ptr)); song->track_number = song_descriptor[i].track_number; song->duration_ms = song_descriptor[i].duration; - song->format = static_cast( + song->format = static_cast( xe::byte_swap(song_descriptor[i].song_format)); if (out_song_handles) { @@ -148,25 +148,24 @@ X_HRESULT XmpApp::XMPPrevious() { return X_E_SUCCESS; } -X_HRESULT XmpApp::XMPGetTitlePlaylistBufferSize(uint32_t xmp_client, +X_HRESULT XmpApp::XMPGetTitlePlaylistBufferSize(apu::XMP_CLIENT xmp_client, uint32_t song_count, uint32_t size_ptr) { /* Note: - Query of size for XamAlloc - the result of the alloc is passed to 0x0007000D. - - xmp_client can range from 0 - 6 but will fail on 1 and set size to zero - if its anything other than 0 or 2. */ XELOGD( "XMPGetTitlePlaylistBufferSize(XMP client: 0x{:08X}, Song count: " "0x{:08X}, Size ptr: 0x{:08X})", - xmp_client, song_count, size_ptr); + uint32_t(xmp_client), song_count, size_ptr); - if (xmp_client == 1 || !size_ptr || !song_count) { + if (xmp_client == apu::XMP_CLIENT::HUD || !size_ptr || !song_count) { return X_E_INVALIDARG; } uint32_t size = 0; - if (xmp_client == 0 || xmp_client == 2) { + if (xmp_client == apu::XMP_CLIENT::Dash || + xmp_client == apu::XMP_CLIENT::Game) { size = song_count * 0x3E8 + 0x88; } // We don't use the storage, so just fudge the number. @@ -186,37 +185,41 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, reinterpret_cast(buffer); uint32_t playlist_handle = xe::load_and_swap( memory_->TranslateVirtual(args->storage_ptr)); - assert_true(args->xmp_client == 0x00000002); + assert_true(args->xmp_client == apu::XMP_CLIENT::Game); return XMPPlayTitlePlaylist(playlist_handle, args->song_handle); } case 0x00070003: { assert_true(!buffer_length || buffer_length == 4); - uint32_t xmp_client = xe::load_and_swap(buffer + 0); - assert_true(xmp_client == 0x00000002); + apu::XMP_CLIENT xmp_client = + static_cast(xe::load_and_swap(buffer)); + assert_true(xmp_client == apu::XMP_CLIENT::Game); return XMPContinue(); } case 0x00070004: { assert_true(!buffer_length || buffer_length == sizeof(XMP_STOP)); XMP_STOP* args = reinterpret_cast(buffer); - assert_true(args->xmp_client == 0x00000002); - return XMPStop(args->unk); + assert_true(args->xmp_client == apu::XMP_CLIENT::Game); + return XMPStop(args->allow_restart); } case 0x00070005: { assert_true(!buffer_length || buffer_length == 4); - uint32_t xmp_client = xe::load_and_swap(buffer + 0); - assert_true(xmp_client == 0x00000002); + apu::XMP_CLIENT xmp_client = + static_cast(xe::load_and_swap(buffer)); + assert_true(xmp_client == apu::XMP_CLIENT::Game); return XMPPause(); } case 0x00070006: { assert_true(!buffer_length || buffer_length == 4); - uint32_t xmp_client = xe::load_and_swap(buffer + 0); - assert_true(xmp_client == 0x00000002); + apu::XMP_CLIENT xmp_client = + static_cast(xe::load_and_swap(buffer)); + assert_true(xmp_client == apu::XMP_CLIENT::Game); return XMPNext(); } case 0x00070007: { assert_true(!buffer_length || buffer_length == 4); - uint32_t xmp_client = xe::load_and_swap(buffer + 0); - assert_true(xmp_client == 0x00000002); + apu::XMP_CLIENT xmp_client = + static_cast(xe::load_and_swap(buffer)); + assert_true(xmp_client == apu::XMP_CLIENT::Game); return XMPPrevious(); } case 0x00070008: { @@ -230,10 +233,10 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, XMP_SET_PLAYBACK_BEHAVIOR* args = reinterpret_cast(buffer); - assert_true(args->xmp_client == 0x00000002 || - args->xmp_client == 0x00000000); + assert_true(args->xmp_client == apu::XMP_CLIENT::Game || + args->xmp_client == apu::XMP_CLIENT::Dash); XELOGD("XMPSetPlaybackBehavior({:08X}, {:08X}, {:08X}, {:08X})", - uint32_t(args->xmp_client), uint32_t(args->playback_mode), + uint32_t(args->xmp_client.get()), uint32_t(args->playback_mode), uint32_t(args->repeat_mode), uint32_t(args->flags)); kernel_state_->emulator()->audio_media_player()->SetPlaybackMode( @@ -250,14 +253,14 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, case 0x00070009: { assert_true(!buffer_length || buffer_length == sizeof(XMP_GET_STATUS)); XMP_GET_STATUS* args = reinterpret_cast(buffer); - assert_true(args->xmp_client == 0x00000002); + assert_true(args->xmp_client == apu::XMP_CLIENT::Game); return XMPGetStatus(args->state_ptr); } case 0x0007000B: { assert_true(!buffer_length || buffer_length == sizeof(XMP_GET_VOLUME)); XMP_GET_VOLUME* args = reinterpret_cast(buffer); - assert_true(args->xmp_client == 0x00000002); + assert_true(args->xmp_client == apu::XMP_CLIENT::Game); XELOGD("XMPGetVolume({:08X})", uint32_t(args->volume_ptr)); xe::store_and_swap( @@ -269,8 +272,8 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, assert_true(!buffer_length || buffer_length == sizeof(XMP_SET_VOLUME)); XMP_SET_VOLUME* args = reinterpret_cast(buffer); - assert_true(args->xmp_client == 0x00000002); - XELOGD("XMPSetVolume({:d}, {:g})", args->xmp_client.get(), + assert_true(args->xmp_client == apu::XMP_CLIENT::Game); + XELOGD("XMPSetVolume({:d}, {:g})", uint32_t(args->xmp_client.get()), float(args->value)); kernel_state_->emulator()->audio_media_player()->SetVolume( float(args->value)); @@ -285,8 +288,8 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, xe::store_and_swap( memory_->TranslateVirtual(args->playlist_handle_ptr), args->storage_ptr); - assert_true(args->xmp_client == 0x00000002 || - args->xmp_client == 0x00000000); + assert_true(args->xmp_client == apu::XMP_CLIENT::Game || + args->xmp_client == apu::XMP_CLIENT::Dash); std::u16string playlist_name; if (!args->playlist_name_ptr) { playlist_name = u""; @@ -307,7 +310,7 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, reinterpret_cast(buffer); auto info = memory_->TranslateVirtual(args->info_ptr); - assert_true(args->xmp_client == 0x00000002); + assert_true(args->xmp_client == apu::XMP_CLIENT::Game); assert_zero(args->unk_ptr); XELOGD("XMPGetCurrentSong({:08X}, {:08X})", uint32_t(args->unk_ptr), uint32_t(args->info_ptr)); @@ -341,8 +344,8 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, uint32_t playlist_handle = xe::load_and_swap( memory_->TranslateVirtual(args->storage_ptr)); - assert_true(args->xmp_client == 0x00000002 || - args->xmp_client == 0x00000000); + assert_true(args->xmp_client == apu::XMP_CLIENT::Game || + args->xmp_client == apu::XMP_CLIENT::Dash); return XMPDeleteTitlePlaylist(playlist_handle); } case 0x0007001A: { @@ -352,21 +355,45 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, XMP_SET_PLAYBACK_CONTROLLER* args = reinterpret_cast(buffer); - assert_true( - (args->xmp_client == 0x00000002 && args->controller == 0x00000000) || - (args->xmp_client == 0x00000000 && args->controller == 0x00000001)); + const bool XMP_User_Dash = + args->xmp_client == apu::XMP_CLIENT::Dash && + args->playback_controller_request == apu::PlaybackController::User; + const bool XMPOverrideBackgroundMusic = + args->xmp_client == apu::XMP_CLIENT::Game && + args->playback_controller_request == apu::PlaybackController::Game; + const bool XMPRestoreBackgroundMusic = + args->xmp_client == apu::XMP_CLIENT::Game && + args->playback_controller_request == apu::PlaybackController::Restore; + + assert_true(XMPOverrideBackgroundMusic || XMPRestoreBackgroundMusic || + XMP_User_Dash); + XELOGD("XMPSetPlaybackController({:08X}, {:08X}, {:08X})", - uint32_t(args->xmp_client), uint32_t(args->controller), - uint32_t(args->playback_client)); + uint32_t(args->xmp_client.get()), + uint32_t(args->playback_controller_request.get()), + uint32_t(args->playback_controller_locked)); - kernel_state_->emulator()->audio_media_player()->SetPlaybackClient( - PlaybackClient(uint32_t(args->playback_client))); + auto media_player = kernel_state_->emulator()->audio_media_player(); + if (args->playback_controller_request == + apu::PlaybackController::Restore) { + media_player->SetXMPClient(apu::XMP_CLIENT::Game); + media_player->SetPlaybackController(apu::PlaybackController::Game); + } else { + media_player->SetXMPClient(args->xmp_client); + media_player->SetPlaybackController( + args->playback_controller_request.get()); + } + + media_player->SetXMPOverride(args->playback_controller_locked.get()); + + // 58411446 kernel_state_->BroadcastNotification( kXNotificationXmpPlaybackControllerChanged, - kernel_state_->emulator() - ->audio_media_player() - ->IsTitleInPlaybackControl()); + media_player->IsXMPOverrideEnabled() + ? false + : media_player->IsTitleInPlaybackControl()); + return X_E_SUCCESS; } case 0x0007001B: { @@ -376,20 +403,36 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, XMP_GET_PLAYBACK_CONTROLLER* args = reinterpret_cast(buffer); - assert_true(args->xmp_client == 0x00000002); + assert_true(args->xmp_client == apu::XMP_CLIENT::Game); XELOGD("XMPGetPlaybackController({:08X}, {:08X}, {:08X})", - uint32_t(args->xmp_client), uint32_t(args->controller_ptr), - uint32_t(args->locked_ptr)); - xe::store_and_swap( - memory_->TranslateVirtual(args->controller_ptr), 0); - xe::store_and_swap(memory_->TranslateVirtual(args->locked_ptr), - 0); + uint32_t(args->xmp_client.get()), + uint32_t(args->playback_controller_ptr), + uint32_t(args->playback_controller_locked_ptr)); + + const auto media_player = kernel_state_->emulator()->audio_media_player(); + + xe::be* controller = + memory_->TranslateVirtual*>( + args->playback_controller_ptr); + + *controller = media_player->GetPlaybackController(); + + xe::be* playback_controller_locked = + memory_->TranslateVirtual*>( + args->playback_controller_locked_ptr); + + *playback_controller_locked = !media_player->IsTitleInPlaybackControl(); if (!XThread::GetCurrentThread()->main_thread()) { // Atrain spawns a thread 82437FD0 to call this in a tight loop forever. xe::threading::Sleep(std::chrono::milliseconds(10)); } + // Assert if game is not in control of playback. + assert_true(media_player->GetPlaybackController() == + apu::PlaybackController::Game); + assert_zero(!media_player->IsTitleInPlaybackControl()); + return X_E_SUCCESS; } case 0x00070025: { @@ -402,7 +445,7 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, reinterpret_cast(buffer); XELOGD("XMPCreateUserPlaylistEnumerator({:08X}, {:08X}, {:08X})", - uint32_t(args->xmp_client), uint32_t(args->flags), + uint32_t(args->xmp_client.get()), uint32_t(args->flags), uint32_t(args->object_ptr)); return X_E_SUCCESS; } @@ -413,11 +456,11 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, XMP_GET_PLAYBACK_BEHAVIOR* args = reinterpret_cast(buffer); - assert_true(args->xmp_client == 0x00000002 || - args->xmp_client == 0x00000000); + assert_true(args->xmp_client == apu::XMP_CLIENT::Game || + args->xmp_client == apu::XMP_CLIENT::Dash); XELOGD("XMPGetPlaybackBehavior({:08X}, {:08X}, {:08X}, {:08X})", - uint32_t(args->xmp_client), uint32_t(args->playback_mode_ptr), - uint32_t(args->repeat_mode_ptr), + uint32_t(args->xmp_client.get()), + uint32_t(args->playback_mode_ptr), uint32_t(args->repeat_mode_ptr), uint32_t(args->playback_flags_ptr)); if (args->playback_mode_ptr) { xe::store_and_swap( @@ -451,13 +494,15 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, XMP_GET_MEDIA_SOURCES* args = reinterpret_cast(buffer); - assert_true(args->xmp_client == 0x00000002 || - args->xmp_client == 0x00000000); + assert_true(args->xmp_client == apu::XMP_CLIENT::Game || + args->xmp_client == apu::XMP_CLIENT::Dash); XELOGD( "XMPGetMediaSources({:08X}, {:08X}, {:08X}, {:08X}, {:08X}), " "unimplemented", - args->xmp_client.get(), args->unk1.get(), args->unk1_ptr.get(), - args->unk2.get(), args->unk2_ptr.get()); + uint32_t(args->xmp_client.get()), + args->get_connected_sources_only.get(), + args->media_resources_ptr.get(), args->max_source.get(), + args->sources_returned_ptr.get()); return X_E_INVALIDARG; } case 0x0007002E: { @@ -474,12 +519,12 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, assert_true(!buffer_length || buffer_length == sizeof(XMP_DASH_INIT)); XMP_DASH_INIT* args = reinterpret_cast(buffer); - assert_true(args->xmp_client == 0x00000002 || - args->xmp_client == 0x00000000); + assert_true(args->xmp_client == apu::XMP_CLIENT::Game || + args->xmp_client == apu::XMP_CLIENT::Dash); XELOGD( "XMPDashInIt({:08X}, {:08X}, {:08X}, {:08X}, {:08X}, {:08X}), " "unimplemented", - args->xmp_client.get(), args->buffer_ptr.get(), + uint32_t(args->xmp_client.get()), args->buffer_ptr.get(), args->buffer_length.get(), args->unk1.get(), args->unk2.get(), args->storage_ptr.get()); return X_E_INVALIDARG; @@ -491,8 +536,8 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, XMP_CAPTURE_OUTPUT* args = reinterpret_cast(buffer); XELOGD("XMPCaptureOutput({:08X}, {:08X}, {:08X}, {:08X})", - args->xmp_client.get(), args->callback.get(), args->context.get(), - args->title_render.get()); + uint32_t(args->xmp_client.get()), args->callback.get(), + args->context.get(), args->title_render.get()); kernel_state_->emulator()->audio_media_player()->SetCaptureCallback( args->callback, args->context, static_cast(args->title_render)); return X_E_SUCCESS; @@ -507,14 +552,14 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, XMP_SET_MEDIA_SOURCE_WORKSPACE* args = reinterpret_cast(buffer); - assert_true(args->xmp_client == 0x00000002 || - args->xmp_client == 0x00000001 || - args->xmp_client == 0x00000000); + assert_true(args->xmp_client == apu::XMP_CLIENT::Game || + args->xmp_client == apu::XMP_CLIENT::HUD || + args->xmp_client == apu::XMP_CLIENT::Dash); XELOGD( "XMPSetMediaSourceWorkspace({:08X}, {:08X}, {:08X}, {:08X}), " "unimplemented", - args->xmp_client.get(), args->unk1.get(), args->storage_ptr.get(), - args->unk2.get()); + uint32_t(args->xmp_client.get()), args->unk1.get(), + args->storage_ptr.get(), args->unk2.get()); return X_E_INVALIDARG; } case 0x00070053: { @@ -522,8 +567,8 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, // picture or video library. It only receives buffer XMP_GET_DASH_INIT_STATE* args = reinterpret_cast(buffer); - XELOGD("XMPGetDashInItState({:08X}, {:08X})", args->xmp_client.get(), - args->dash_init_state_ptr.get()); + XELOGD("XMPGetDashInItState({:08X}, {:08X})", + uint32_t(args->xmp_client.get()), args->dash_init_state_ptr.get()); xe::store_and_swap( memory_->TranslateVirtual(args->dash_init_state_ptr), diff --git a/src/xenia/kernel/xam/apps/xmp_app.h b/src/xenia/kernel/xam/apps/xmp_app.h index 8d7afa044..d3e0070d2 100644 --- a/src/xenia/kernel/xam/apps/xmp_app.h +++ b/src/xenia/kernel/xam/apps/xmp_app.h @@ -13,6 +13,28 @@ #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/xam/app_manager.h" +namespace xe { +namespace apu { +enum class XMP_CLIENT : uint32_t { + Dash, + HUD, + Game, + Remote, + MusicPlayer, + MSAL, + MCE, +}; + +enum class PlaybackController : uint32_t { + Game, + User, + Dash, + MCE, + Restore, +}; +} // namespace apu +} // namespace xe + namespace xe { namespace kernel { namespace xam { @@ -53,20 +75,20 @@ struct XMP_SONGINFO { static_assert_size(XMP_SONGINFO, 0x3E0); struct XMP_PLAY_TITLE_PLAYLIST { - xe::be xmp_client; + xe::be xmp_client; xe::be storage_ptr; xe::be song_handle; }; static_assert_size(XMP_PLAY_TITLE_PLAYLIST, 0xC); struct XMP_STOP { - xe::be xmp_client; - xe::be unk; + xe::be xmp_client; + xe::be allow_restart; }; static_assert_size(XMP_STOP, 0x8); struct XMP_SET_PLAYBACK_BEHAVIOR { - xe::be xmp_client; + xe::be xmp_client; xe::be playback_mode; xe::be repeat_mode; xe::be flags; @@ -74,25 +96,25 @@ struct XMP_SET_PLAYBACK_BEHAVIOR { static_assert_size(XMP_SET_PLAYBACK_BEHAVIOR, 0x10); struct XMP_GET_STATUS { - xe::be xmp_client; + xe::be xmp_client; xe::be state_ptr; }; static_assert_size(XMP_GET_STATUS, 0x8); struct XMP_GET_VOLUME { - xe::be xmp_client; + xe::be xmp_client; xe::be volume_ptr; }; static_assert_size(XMP_GET_VOLUME, 0x8); struct XMP_SET_VOLUME { - xe::be xmp_client; + xe::be xmp_client; xe::be value; }; static_assert_size(XMP_SET_VOLUME, 0x8); struct XMP_CREATE_TITLE_PLAYLIST { - xe::be xmp_client; + xe::be xmp_client; xe::be storage_ptr; xe::be storage_size; xe::be songs_ptr; @@ -105,41 +127,41 @@ struct XMP_CREATE_TITLE_PLAYLIST { static_assert_size(XMP_CREATE_TITLE_PLAYLIST, 0x24); struct XMP_GET_CURRENT_SONG { - xe::be xmp_client; + xe::be xmp_client; xe::be unk_ptr; xe::be info_ptr; }; static_assert_size(XMP_GET_CURRENT_SONG, 0xC); struct XMP_DELETE_TITLE_PLAYLIST { - xe::be xmp_client; + xe::be xmp_client; xe::be storage_ptr; }; static_assert_size(XMP_DELETE_TITLE_PLAYLIST, 0x8); struct XMP_SET_PLAYBACK_CONTROLLER { - xe::be xmp_client; - xe::be controller; - xe::be playback_client; + xe::be xmp_client; + xe::be playback_controller_request; + xe::be playback_controller_locked; }; static_assert_size(XMP_SET_PLAYBACK_CONTROLLER, 0xC); struct XMP_GET_PLAYBACK_CONTROLLER { - xe::be xmp_client; - xe::be controller_ptr; - xe::be locked_ptr; + xe::be xmp_client; + xe::be playback_controller_ptr; + xe::be playback_controller_locked_ptr; }; static_assert_size(XMP_GET_PLAYBACK_CONTROLLER, 0xC); struct XMP_CREATE_USER_PLAYLIST_ENUMERATOR { - xe::be xmp_client; + xe::be xmp_client; xe::be flags; xe::be object_ptr; }; static_assert_size(XMP_CREATE_USER_PLAYLIST_ENUMERATOR, 0xC); struct XMP_GET_PLAYBACK_BEHAVIOR { - xe::be xmp_client; + xe::be xmp_client; xe::be playback_mode_ptr; xe::be repeat_mode_ptr; xe::be playback_flags_ptr; @@ -147,23 +169,23 @@ struct XMP_GET_PLAYBACK_BEHAVIOR { static_assert_size(XMP_GET_PLAYBACK_BEHAVIOR, 0x10); struct XMP_GET_MEDIA_SOURCES { - xe::be xmp_client; - xe::be unk1; - xe::be unk1_ptr; - xe::be unk2; - xe::be unk2_ptr; + xe::be xmp_client; + xe::be get_connected_sources_only; + xe::be media_resources_ptr; // *MSAL_MEDIASOURCEINFO + xe::be max_source; + xe::be sources_returned_ptr; }; static_assert_size(XMP_GET_MEDIA_SOURCES, 0x14); struct XMP_GET_TITLE_PLAYLIST_BUFFER_SIZE { - xe::be xmp_client; + xe::be xmp_client; xe::be song_count; xe::be size_ptr; }; static_assert_size(XMP_GET_TITLE_PLAYLIST_BUFFER_SIZE, 0xC); struct XMP_DASH_INIT { - xe::be xmp_client; + xe::be xmp_client; xe::be buffer_ptr; // used by XamEnumerate xe::be buffer_length; // used by XamEnumerate xe::be unk1; @@ -173,7 +195,7 @@ struct XMP_DASH_INIT { static_assert_size(XMP_DASH_INIT, 0x18); struct XMP_CAPTURE_OUTPUT { - xe::be xmp_client; + xe::be xmp_client; xe::be callback; xe::be context; xe::be title_render; @@ -181,7 +203,7 @@ struct XMP_CAPTURE_OUTPUT { static_assert_size(XMP_CAPTURE_OUTPUT, 0x10); struct XMP_SET_MEDIA_SOURCE_WORKSPACE { - xe::be xmp_client; + xe::be xmp_client; xe::be unk1; xe::be storage_ptr; xe::be unk2; @@ -189,7 +211,7 @@ struct XMP_SET_MEDIA_SOURCE_WORKSPACE { static_assert_size(XMP_SET_MEDIA_SOURCE_WORKSPACE, 0x10); struct XMP_GET_DASH_INIT_STATE { - xe::be xmp_client; + xe::be xmp_client; xe::be dash_init_state_ptr; }; static_assert_size(XMP_GET_DASH_INIT_STATE, 0x8); @@ -201,10 +223,6 @@ class XmpApp : public App { kPlaying = 1, kPaused = 2, }; - enum class PlaybackClient : uint32_t { - kSystem = 0, - kTitle = 1, - }; enum class PlaybackMode : uint32_t { kInOrder = 0, kShuffle = 1, @@ -217,12 +235,12 @@ class XmpApp : public App { kDefault = 0, kAutoPause = 1, }; - struct Song { - enum class Format : uint32_t { - kWma = 0, - kMp3 = 1, - }; + enum class SongFormat : uint32_t { + kWma = 0, + kMp3 = 1, + }; + struct Song { uint32_t handle; std::u16string file_path; std::u16string name; @@ -232,7 +250,7 @@ class XmpApp : public App { std::u16string genre; uint32_t track_number; uint32_t duration_ms; - Format format; + SongFormat format; }; struct Playlist { uint32_t handle; @@ -258,7 +276,7 @@ class XmpApp : public App { X_HRESULT XMPPause(); X_HRESULT XMPNext(); X_HRESULT XMPPrevious(); - X_HRESULT XMPGetTitlePlaylistBufferSize(uint32_t xmp_client, + X_HRESULT XMPGetTitlePlaylistBufferSize(apu::XMP_CLIENT xmp_client, uint32_t song_count, uint32_t storage_ptr);