From b6b27e621a44dba43e57e94270370ca04514cdb9 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sun, 11 Jan 2015 00:28:24 -0800 Subject: [PATCH] Enough XMP to play (fake) play media. --- src/poly/memory.h | 14 + src/xenia/kernel/app.cc | 2 +- src/xenia/kernel/app.h | 2 +- src/xenia/kernel/apps/xmp_app.cc | 316 +++++++++++++++---- src/xenia/kernel/apps/xmp_app.h | 74 ++++- src/xenia/kernel/objects/xnotify_listener.cc | 2 +- 6 files changed, 343 insertions(+), 67 deletions(-) diff --git a/src/poly/memory.h b/src/poly/memory.h index 66918a0eb..c4e5b4b90 100644 --- a/src/poly/memory.h +++ b/src/poly/memory.h @@ -305,6 +305,20 @@ template <> inline void store_and_swap(void* mem, double value) { *reinterpret_cast(mem) = byte_swap(value); } +template <> +inline void store_and_swap(void* mem, std::string value) { + for (auto i = 0; i < value.size(); ++i) { + poly::store_and_swap(reinterpret_cast(mem) + i, + value[i]); + } +} +template <> +inline void store_and_swap(void* mem, std::wstring value) { + for (auto i = 0; i < value.size(); ++i) { + poly::store_and_swap(reinterpret_cast(mem) + i, + value[i]); + } +} template struct be { diff --git a/src/xenia/kernel/app.cc b/src/xenia/kernel/app.cc index bb2e5a1bc..3216a32fc 100644 --- a/src/xenia/kernel/app.cc +++ b/src/xenia/kernel/app.cc @@ -37,7 +37,7 @@ X_RESULT XAppManager::DispatchMessageSync(uint32_t app_id, uint32_t message, X_RESULT XAppManager::DispatchMessageAsync(uint32_t app_id, uint32_t message, uint32_t buffer_ptr, - size_t buffer_length) { + uint32_t buffer_length) { const auto& it = app_lookup_.find(app_id); if (it == app_lookup_.end()) { return X_ERROR_NOT_FOUND; diff --git a/src/xenia/kernel/app.h b/src/xenia/kernel/app.h index 3ff461cc0..1608a4162 100644 --- a/src/xenia/kernel/app.h +++ b/src/xenia/kernel/app.h @@ -44,7 +44,7 @@ class XAppManager { X_RESULT DispatchMessageSync(uint32_t app_id, uint32_t message, uint32_t buffer_ptr, uint32_t buffer_length); X_RESULT DispatchMessageAsync(uint32_t app_id, uint32_t message, - uint32_t buffer_ptr, size_t buffer_length); + uint32_t buffer_ptr, uint32_t buffer_length); private: std::vector> apps_; diff --git a/src/xenia/kernel/apps/xmp_app.cc b/src/xenia/kernel/apps/xmp_app.cc index 68a906e4a..3d04be800 100644 --- a/src/xenia/kernel/apps/xmp_app.cc +++ b/src/xenia/kernel/apps/xmp_app.cc @@ -9,81 +9,204 @@ #include +#include + namespace xe { namespace kernel { namespace apps { XXMPApp::XXMPApp(KernelState* kernel_state) : XApp(kernel_state, 0xFA), - status_(Status::kStopped), + state_(State::kIdle), disabled_(0), - unknown_state1_(0), - unknown_state2_(0), + playback_mode_(PlaybackMode::kUnknown), + repeat_mode_(RepeatMode::kUnknown), unknown_flags_(0), - unknown_float_(0.0f) {} + volume_(0.0f), + active_playlist_(nullptr), + active_song_index_(0), + next_playlist_handle_(1), + next_song_handle_(1) {} -X_RESULT XXMPApp::XMPGetStatus(uint32_t status_ptr) { +X_RESULT XXMPApp::XMPGetStatus(uint32_t state_ptr) { // Some stupid games will hammer this on a thread - induce a delay // here to keep from starving real threads. Sleep(1); - XELOGD("XMPGetStatus(%.8X)", status_ptr); - poly::store_and_swap(membase_ + status_ptr, - static_cast(status_)); - OnStatusChanged(); + XELOGD("XMPGetStatus(%.8X)", state_ptr); + poly::store_and_swap(membase_ + state_ptr, + static_cast(state_)); + return X_ERROR_SUCCESS; +} + +X_RESULT XXMPApp::XMPCreateTitlePlaylist( + uint32_t songs_ptr, uint32_t song_count, uint32_t playlist_name_ptr, + std::wstring playlist_name, uint32_t flags, uint32_t out_song_handles, + uint32_t out_playlist_handle) { + XELOGD("XMPCreateTitlePlaylist(%.8X, %.8X, %.8X(%s), %.8X, %.8X, %.8X)", + songs_ptr, song_count, playlist_name_ptr, + poly::to_string(playlist_name).c_str(), flags, out_song_handles, + out_playlist_handle); + auto playlist = std::make_unique(); + playlist->handle = ++next_playlist_handle_; + playlist->name = std::move(playlist_name); + playlist->flags = flags; + for (uint32_t i = 0; i < song_count; ++i) { + auto song = std::make_unique(); + song->handle = ++next_song_handle_; + uint8_t* song_base = membase_ + songs_ptr + (i * 36); + song->file_path = poly::load_and_swap( + membase_ + poly::load_and_swap(song_base + 0)); + song->name = poly::load_and_swap( + membase_ + poly::load_and_swap(song_base + 4)); + song->artist = poly::load_and_swap( + membase_ + poly::load_and_swap(song_base + 8)); + song->album = poly::load_and_swap( + membase_ + poly::load_and_swap(song_base + 12)); + song->album_artist = poly::load_and_swap( + membase_ + poly::load_and_swap(song_base + 16)); + song->genre = poly::load_and_swap( + membase_ + poly::load_and_swap(song_base + 20)); + song->track_number = poly::load_and_swap(song_base + 24); + song->duration_ms = poly::load_and_swap(song_base + 28); + song->format = static_cast( + poly::load_and_swap(song_base + 32)); + if (out_song_handles) { + poly::store_and_swap(membase_ + out_song_handles + (i * 4), + song->handle); + } + playlist->songs.emplace_back(std::move(song)); + } + poly::store_and_swap(membase_ + out_playlist_handle, + playlist->handle); + + std::lock_guard lock(mutex_); + playlists_.insert({playlist->handle, playlist.get()}); + playlist.release(); + return X_ERROR_SUCCESS; +} + +X_RESULT XXMPApp::XMPDeleteTitlePlaylist(uint32_t playlist_handle) { + XELOGD("XMPDeleteTitlePlaylist(%.8X)", playlist_handle); + std::lock_guard lock(mutex_); + auto it = playlists_.find(playlist_handle); + if (it == playlists_.end()) { + XELOGE("Playlist %.8X not found", playlist_handle); + return X_ERROR_NOT_FOUND; + } + auto playlist = it->second; + if (playlist == active_playlist_) { + XMPStop(0); + } + playlists_.erase(it); + delete playlist; + return X_ERROR_SUCCESS; +} + +X_RESULT XXMPApp::XMPPlayTitlePlaylist(uint32_t playlist_handle, + uint32_t song_handle) { + XELOGD("XMPPlayTitlePlaylist(%.8X, %.8X)", playlist_handle, song_handle); + Playlist* playlist = nullptr; + { + std::lock_guard lock(mutex_); + auto it = playlists_.find(playlist_handle); + if (it == playlists_.end()) { + XELOGE("Playlist %.8X not found", playlist_handle); + return X_ERROR_NOT_FOUND; + } + playlist = it->second; + } + + if (disabled_) { + // Ignored because we aren't enabled? + XELOGW("Ignoring XMPPlayTitlePlaylist because disabled"); + return X_ERROR_SUCCESS; + } + + // Start playlist? + XELOGW("Playlist playback not supported"); + active_playlist_ = playlist; + active_song_index_ = 0; + state_ = State::kPlaying; + OnStateChanged(); return X_ERROR_SUCCESS; } X_RESULT XXMPApp::XMPContinue() { XELOGD("XMPContinue()"); - if (status_ == Status::kPaused) { - status_ = Status::kPlaying; + if (state_ == State::kPaused) { + state_ = State::kPlaying; } - OnStatusChanged(); + OnStateChanged(); return X_ERROR_SUCCESS; } X_RESULT XXMPApp::XMPStop(uint32_t unk) { assert_zero(unk); XELOGD("XMPStop(%.8X)", unk); - status_ = Status::kStopped; - OnStatusChanged(); + active_playlist_ = nullptr; // ? + active_song_index_ = 0; + state_ = State::kIdle; + OnStateChanged(); return X_ERROR_SUCCESS; } X_RESULT XXMPApp::XMPPause() { XELOGD("XMPPause()"); - if (status_ == Status::kPlaying) { - status_ = Status::kPaused; + if (state_ == State::kPlaying) { + state_ = State::kPaused; } - OnStatusChanged(); + OnStateChanged(); return X_ERROR_SUCCESS; } X_RESULT XXMPApp::XMPNext() { XELOGD("XMPNext()"); - status_ = Status::kPlaying; - OnStatusChanged(); + if (!active_playlist_) { + return X_ERROR_NOT_FOUND; + } + state_ = State::kPlaying; + active_song_index_ = + (active_song_index_ + 1) % active_playlist_->songs.size(); + OnStateChanged(); return X_ERROR_SUCCESS; } X_RESULT XXMPApp::XMPPrevious() { XELOGD("XMPPrevious()"); - status_ = Status::kPlaying; - OnStatusChanged(); + if (!active_playlist_) { + return X_ERROR_NOT_FOUND; + } + state_ = State::kPlaying; + if (!active_song_index_) { + active_song_index_ = static_cast(active_playlist_->songs.size()) - 1; + } else { + --active_song_index_; + } + OnStateChanged(); return X_ERROR_SUCCESS; } -void XXMPApp::OnStatusChanged() { - kernel_state_->BroadcastNotification(kMsgStatusChanged, - static_cast(status_)); +void XXMPApp::OnStateChanged() { + kernel_state_->BroadcastNotification(kMsgStateChanged, + static_cast(state_)); } X_RESULT XXMPApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, uint32_t buffer_length) { // NOTE: buffer_length may be zero or valid. - // http://freestyledash.googlecode.com/svn-history/r1/trunk/Freestyle/Scenes/Media/Music/ScnMusic.cpp switch (message) { + case 0x00070002: { + assert_true(!buffer_length || buffer_length == 12); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + uint32_t playlist_handle = + poly::load_and_swap(membase_ + buffer_ptr + 4); + uint32_t song_handle = + poly::load_and_swap(membase_ + buffer_ptr + 8); // 0? + assert_true(xmp_client == 0x00000002); + return XMPPlayTitlePlaylist(playlist_handle, song_handle); + } case 0x00070003: { assert_true(!buffer_length || buffer_length == 4); uint32_t xmp_client = @@ -124,26 +247,29 @@ X_RESULT XXMPApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, assert_true(!buffer_length || buffer_length == 16); uint32_t xmp_client = poly::load_and_swap(membase_ + buffer_ptr + 0); - uint32_t unk1 = poly::load_and_swap(membase_ + buffer_ptr + 4); - uint32_t unk2 = poly::load_and_swap(membase_ + buffer_ptr + 8); + uint32_t playback_mode = + poly::load_and_swap(membase_ + buffer_ptr + 4); + uint32_t repeat_mode = + poly::load_and_swap(membase_ + buffer_ptr + 8); uint32_t flags = poly::load_and_swap(membase_ + buffer_ptr + 12); assert_true(xmp_client == 0x00000002); - XELOGD("XMPSetState?(%.8X, %.8X, %.8X)", unk1, unk2, flags); - unknown_state1_ = unk1; - unknown_state2_ = unk2; + XELOGD("XMPSetPlaybackBehavior(%.8X, %.8X, %.8X)", playback_mode, + repeat_mode, flags); + playback_mode_ = static_cast(playback_mode); + repeat_mode_ = static_cast(repeat_mode); unknown_flags_ = flags; - kernel_state_->BroadcastNotification(kMsgStateChanged, 0); + kernel_state_->BroadcastNotification(kMsgPlaybackBehaviorChanged, 0); return X_ERROR_SUCCESS; } case 0x00070009: { assert_true(!buffer_length || buffer_length == 8); uint32_t xmp_client = poly::load_and_swap(membase_ + buffer_ptr + 0); - uint32_t status_ptr = poly::load_and_swap( + uint32_t state_ptr = poly::load_and_swap( membase_ + buffer_ptr + 4); // out ptr to 4b - expect 0 assert_true(xmp_client == 0x00000002); - return XMPGetStatus(status_ptr); + return XMPGetStatus(state_ptr); } case 0x0007000B: { assert_true(!buffer_length || buffer_length == 8); @@ -152,8 +278,8 @@ X_RESULT XXMPApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, uint32_t float_ptr = poly::load_and_swap( membase_ + buffer_ptr + 4); // out ptr to 4b - floating point assert_true(xmp_client == 0x00000002); - XELOGD("XMPGetFloat?(%.8X)", float_ptr); - poly::store_and_swap(membase_ + float_ptr, unknown_float_); + XELOGD("XMPGetVolume(%.8X)", float_ptr); + poly::store_and_swap(membase_ + float_ptr, volume_); return X_ERROR_SUCCESS; } case 0x0007000C: { @@ -162,21 +288,96 @@ X_RESULT XXMPApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, poly::load_and_swap(membase_ + buffer_ptr + 0); float float_value = poly::load_and_swap(membase_ + buffer_ptr + 4); assert_true(xmp_client == 0x00000002); - XELOGD("XMPSetFloat?(%g)", float_value); - unknown_float_ = float_value; + XELOGD("XMPSetVolume(%g)", float_value); + volume_ = float_value; return X_ERROR_SUCCESS; } + case 0x0007000D: { + assert_true(!buffer_length || buffer_length == 36); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + uint32_t dummy_alloc_ptr = + poly::load_and_swap(membase_ + buffer_ptr + 4); + uint32_t dummy_alloc_size = + poly::load_and_swap(membase_ + buffer_ptr + 8); + uint32_t songs_ptr = + poly::load_and_swap(membase_ + buffer_ptr + 12); + uint32_t song_count = + poly::load_and_swap(membase_ + buffer_ptr + 16); + uint32_t playlist_name_ptr = + poly::load_and_swap(membase_ + buffer_ptr + 20); + uint32_t flags = + poly::load_and_swap(membase_ + buffer_ptr + 24); + uint32_t song_handles_ptr = + poly::load_and_swap(membase_ + buffer_ptr + 28); // 0? + uint32_t playlist_handle_ptr = + poly::load_and_swap(membase_ + buffer_ptr + 32); + assert_true(xmp_client == 0x00000002); + auto playlist_name = + poly::load_and_swap(membase_ + playlist_name_ptr); + // dummy_alloc_ptr is the result of a XamAlloc of dummy_alloc_size. + assert_true(dummy_alloc_size == song_count * 128); + return XMPCreateTitlePlaylist(songs_ptr, song_count, playlist_name_ptr, + playlist_name, flags, song_handles_ptr, + playlist_handle_ptr); + } + case 0x0007000E: { + assert_true(!buffer_length || buffer_length == 12); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + uint32_t unk_ptr = + poly::load_and_swap(membase_ + buffer_ptr + 4); // 0 + uint32_t info_ptr = + poly::load_and_swap(membase_ + buffer_ptr + 8); + assert_true(xmp_client == 0x00000002); + assert_zero(unk_ptr); + XELOGE("XMPGetInfo?(%.8X, %.8X)", unk_ptr, info_ptr); + if (!active_playlist_) { + return X_ERROR_NOT_FOUND; + } + auto& song = active_playlist_->songs[active_song_index_]; + poly::store_and_swap(membase_ + info_ptr + 0, song->handle); + poly::store_and_swap(membase_ + info_ptr + 4 + 572 + 0, + song->name); + poly::store_and_swap(membase_ + info_ptr + 4 + 572 + 40, + song->artist); + poly::store_and_swap(membase_ + info_ptr + 4 + 572 + 80, + song->album); + poly::store_and_swap(membase_ + info_ptr + 4 + 572 + 120, + song->album_artist); + poly::store_and_swap(membase_ + info_ptr + 4 + 572 + 160, + song->genre); + poly::store_and_swap(membase_ + info_ptr + 4 + 572 + 200, + song->track_number); + poly::store_and_swap(membase_ + info_ptr + 4 + 572 + 204, + song->duration_ms); + poly::store_and_swap(membase_ + info_ptr + 4 + 572 + 208, + static_cast(song->format)); + return X_ERROR_SUCCESS; + } + case 0x00070013: { + assert_true(!buffer_length || buffer_length == 8); + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + uint32_t playlist_handle = + poly::load_and_swap(membase_ + buffer_ptr + 4); + assert_true(xmp_client == 0x00000002); + return XMPDeleteTitlePlaylist(playlist_handle); + } case 0x0007001A: { assert_true(!buffer_length || buffer_length == 12); uint32_t xmp_client = poly::load_and_swap(membase_ + buffer_ptr + 0); uint32_t unk1 = poly::load_and_swap(membase_ + buffer_ptr + 4); - uint32_t disabled = + uint32_t enabled = poly::load_and_swap(membase_ + buffer_ptr + 8); assert_true(xmp_client == 0x00000002); assert_zero(unk1); - XELOGD("XMPSetDisabled(%.8X, %.8X)", unk1, disabled); - disabled_ = disabled; + XELOGD("XMPSetEnabled(%.8X, %.8X)", unk1, enabled); + disabled_ = enabled; + if (disabled_) { + XMPStop(0); + } kernel_state_->BroadcastNotification(kMsgDisableChanged, disabled_); return X_ERROR_SUCCESS; } @@ -189,40 +390,47 @@ X_RESULT XXMPApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, uint32_t disabled_ptr = poly::load_and_swap( membase_ + buffer_ptr + 8); // out ptr to 4b - expect 1 (to skip) assert_true(xmp_client == 0x00000002); - XELOGD("XMPGetDisabled(%.8X, %.8X)", unk_ptr, disabled_ptr); + XELOGD("XMPGetEnabled(%.8X, %.8X)", unk_ptr, disabled_ptr); poly::store_and_swap(membase_ + unk_ptr, 0); poly::store_and_swap(membase_ + disabled_ptr, disabled_); + // Atrain spawns a thread 82437FD0 to call this in a tight loop forever. + poly::threading::Sleep(std::chrono::milliseconds(10)); return X_ERROR_SUCCESS; } case 0x00070029: { assert_true(!buffer_length || buffer_length == 16); uint32_t xmp_client = poly::load_and_swap(membase_ + buffer_ptr + 0); - uint32_t unk1_ptr = + uint32_t playback_mode_ptr = poly::load_and_swap(membase_ + buffer_ptr + 4); - uint32_t unk2_ptr = + uint32_t repeat_mode_ptr = poly::load_and_swap(membase_ + buffer_ptr + 8); uint32_t unk3_ptr = poly::load_and_swap(membase_ + buffer_ptr + 12); assert_true(xmp_client == 0x00000002); - XELOGD("XMPGetState?(%.8X, %.8X, %.8X)", unk1_ptr, unk2_ptr, unk3_ptr); - poly::store_and_swap(membase_ + unk1_ptr, unknown_state1_); - poly::store_and_swap(membase_ + unk2_ptr, unknown_state2_); + XELOGD("XMPGetPlaybackBehavior(%.8X, %.8X, %.8X)", playback_mode_ptr, + repeat_mode_ptr, unk3_ptr); + poly::store_and_swap(membase_ + playback_mode_ptr, + static_cast(playback_mode_)); + poly::store_and_swap(membase_ + repeat_mode_ptr, + static_cast(repeat_mode_)); poly::store_and_swap(membase_ + unk3_ptr, unknown_flags_); return X_ERROR_SUCCESS; } case 0x0007002E: { assert_true(!buffer_length || buffer_length == 12); - // 00000002 00000003 20049ce0 - uint32_t xmp_client = poly::load_and_swap( - membase_ + buffer_ptr + 0); // 0x00000002 - uint32_t unk1 = poly::load_and_swap(membase_ + buffer_ptr + - 4); // 0x00000003 - uint32_t unk_ptr = + // Query of size for XamAlloc - the result of the alloc is passed to + // 0x0007000D. + uint32_t xmp_client = + poly::load_and_swap(membase_ + buffer_ptr + 0); + uint32_t song_count = + poly::load_and_swap(membase_ + buffer_ptr + 4); + uint32_t size_ptr = poly::load_and_swap(membase_ + buffer_ptr + 8); assert_true(xmp_client == 0x00000002); - // - break; + // We don't use the storage, so just fudge the number. + poly::store_and_swap(membase_ + size_ptr, song_count * 128); + return X_ERROR_SUCCESS; } } XELOGE("Unimplemented XMsg message app=%.8X, msg=%.8X, arg1=%.8X, arg2=%.8X", diff --git a/src/xenia/kernel/apps/xmp_app.h b/src/xenia/kernel/apps/xmp_app.h index a9fbe76b7..0b1658f17 100644 --- a/src/xenia/kernel/apps/xmp_app.h +++ b/src/xenia/kernel/apps/xmp_app.h @@ -10,6 +10,12 @@ #ifndef XENIA_KERNEL_XBOXKRNL_APPS_XMP_APP_H_ #define XENIA_KERNEL_XBOXKRNL_APPS_XMP_APP_H_ +#include +#include +#include +#include +#include + #include #include #include @@ -18,18 +24,59 @@ namespace xe { namespace kernel { namespace apps { +// Only source of docs for a lot of these functions: +// http://freestyledash.googlecode.com/svn-history/r1/trunk/Freestyle/Scenes/Media/Music/ScnMusic.cpp + class XXMPApp : public XApp { public: - enum class Status : uint32_t { - kStopped = 0, + enum class State : uint32_t { + kIdle = 0, kPlaying = 1, kPaused = 2, }; + enum class PlaybackMode : uint32_t { + // kInOrder = ?, + kUnknown = 0, + }; + enum class RepeatMode : uint32_t { + // kNoRepeat = ?, + kUnknown = 0, + }; + struct Song { + enum class Format : uint32_t { + kWma = 0, + kMp3 = 1, + }; + + uint32_t handle; + std::wstring file_path; + std::wstring name; + std::wstring artist; + std::wstring album; + std::wstring album_artist; + std::wstring genre; + uint32_t track_number; + uint32_t duration_ms; + Format format; + }; + struct Playlist { + uint32_t handle; + std::wstring name; + uint32_t flags; + std::vector> songs; + }; XXMPApp(KernelState* kernel_state); X_RESULT XMPGetStatus(uint32_t status_ptr); + X_RESULT XMPCreateTitlePlaylist(uint32_t songs_ptr, uint32_t song_count, + uint32_t playlist_name_ptr, + std::wstring playlist_name, uint32_t flags, + uint32_t out_song_handles, + uint32_t out_playlist_handle); + X_RESULT XMPDeleteTitlePlaylist(uint32_t playlist_handle); + X_RESULT XMPPlayTitlePlaylist(uint32_t playlist_handle, uint32_t song_handle); X_RESULT XMPContinue(); X_RESULT XMPStop(uint32_t unk); X_RESULT XMPPause(); @@ -40,18 +87,25 @@ class XXMPApp : public XApp { uint32_t buffer_length) override; private: - static const uint32_t kMsgStatusChanged = 0xA000001; - static const uint32_t kMsgStateChanged = 0xA000002; - static const uint32_t kMsgDisableChanged = 0xA000003; + static const uint32_t kMsgStateChanged = 0x0A000001; + static const uint32_t kMsgPlaybackBehaviorChanged = 0x0A000002; + static const uint32_t kMsgDisableChanged = 0x0A000003; - void OnStatusChanged(); + void OnStateChanged(); - Status status_; + State state_; uint32_t disabled_; - uint32_t unknown_state1_; - uint32_t unknown_state2_; + PlaybackMode playback_mode_; + RepeatMode repeat_mode_; uint32_t unknown_flags_; - float unknown_float_; + float volume_; + Playlist* active_playlist_; + int active_song_index_; + + std::mutex mutex_; + std::unordered_map playlists_; + uint32_t next_playlist_handle_; + uint32_t next_song_handle_; }; } // namespace apps diff --git a/src/xenia/kernel/objects/xnotify_listener.cc b/src/xenia/kernel/objects/xnotify_listener.cc index 738a5440d..8825de59d 100644 --- a/src/xenia/kernel/objects/xnotify_listener.cc +++ b/src/xenia/kernel/objects/xnotify_listener.cc @@ -36,7 +36,7 @@ void XNotifyListener::Initialize(uint64_t mask) { void XNotifyListener::EnqueueNotification(XNotificationID id, uint32_t data) { // Ignore if the notification doesn't match our mask. - if ((mask_ & uint64_t(1 << ((id >> 25) + 1))) == 0) { + if ((mask_ & uint64_t(1 << (id >> 25))) == 0) { return; }