Skip to content

Commit

Permalink
Merge pull request #8 from xenia-canary/XMP_DedicatedClass
Browse files Browse the repository at this point in the history
[XMP] Added dedicated AudioMediaPlayer class
  • Loading branch information
backgamon authored Oct 28, 2024
2 parents 90fc07e + 7dab812 commit e500338
Show file tree
Hide file tree
Showing 9 changed files with 770 additions and 449 deletions.
473 changes: 473 additions & 0 deletions src/xenia/apu/audio_media_player.cc

Large diffs are not rendered by default.

124 changes: 124 additions & 0 deletions src/xenia/apu/audio_media_player.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2024 Xenia Canary. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/

#ifndef XENIA_APU_AUDIO_MEDIA_PLAYER_H_
#define XENIA_APU_AUDIO_MEDIA_PLAYER_H_

#include "xenia/apu/audio_system.h"
#include "xenia/kernel/xam/apps/xmp_app.h"

namespace xe {
namespace apu {

using XmpApp = kernel::xam::apps::XmpApp;

class AudioMediaPlayer {
public:
AudioMediaPlayer(apu::AudioSystem* audio_system,
kernel::KernelState* kernel_state);
~AudioMediaPlayer();

void Setup();

X_STATUS Play(uint32_t playlist_handle, uint32_t song_handle);
X_STATUS Next();
X_STATUS Previous();

void Stop();
void Pause();
void Continue();

XmpApp::State GetState() const { return state_; }

X_STATUS SetVolume(float volume);
float GetVolume() const { return volume_; }

void SetPlaybackMode(XmpApp::PlaybackMode playback_mode) {
playback_mode_ = playback_mode;
}
XmpApp::PlaybackMode GetPlaybackMode() const { return playback_mode_; }

void SetRepeatMode(XmpApp::RepeatMode repeat_mode) {
repeat_mode_ = repeat_mode;
}
XmpApp::RepeatMode GetRepeatMode() { return repeat_mode_; }

void SetPlaybackFlags(XmpApp::PlaybackFlags playback_flags) {
playback_flags_ = playback_flags;
}
XmpApp::PlaybackFlags GetPlaybackFlags() const { return playback_flags_; }

void SetPlaybackClient(XmpApp::PlaybackClient playback_client) {
playback_client_ = playback_client;
}

XmpApp::PlaybackClient GetPlaybackClient() const { return playback_client_; }

bool IsTitleInPlaybackControl() const {
return playback_client_ == XmpApp::PlaybackClient::kTitle ||
is_title_rendering_enabled_;
}

void SetCaptureCallback(uint32_t callback, uint32_t context,
bool title_render);

void AddPlaylist(uint32_t handle, std::unique_ptr<XmpApp::Playlist> playlist);
void RemovePlaylist(uint32_t handle);

XmpApp::Song* GetCurrentSong() const { return active_song_; }

void ProcessAudioBuffer(std::vector<float>* buffer);

private:
void OnStateChanged();

void Play();
void WorkerThreadMain();
bool LoadSongToMemory(std::vector<uint8_t>* buffer);

XmpApp::State state_ = XmpApp::State::kIdle;
XmpApp::PlaybackClient playback_client_ = XmpApp::PlaybackClient::kSystem;
XmpApp::PlaybackMode playback_mode_ = XmpApp::PlaybackMode::kInOrder;
XmpApp::RepeatMode repeat_mode_ = XmpApp::RepeatMode::kPlaylist;
XmpApp::PlaybackFlags playback_flags_ = XmpApp::PlaybackFlags::kDefault;
float volume_ = 1.0f;

std::unordered_map<uint32_t, std::unique_ptr<XmpApp::Playlist>> playlists_;
XmpApp::Playlist* active_playlist_;
XmpApp::Song* active_song_;

size_t song_index_ = 0;

uint32_t callback_ = 0;
uint32_t callback_context_ = 0;
uint32_t sample_buffer_ptr_ = 0;
bool is_title_rendering_enabled_ = false;

AudioSystem* audio_system_ = nullptr;
kernel::KernelState* kernel_state_ = nullptr;

xe::global_critical_region global_critical_region_;
std::atomic<bool> worker_running_ = {false};
kernel::object_ref<kernel::XHostThread> worker_thread_;
xe::threading::Fence resume_fence_; // Signaled when resume requested.

// Driver part - This should be integrated into audio_system, but it isn't
// really compatible with it.
std::unique_ptr<AudioDriver> driver_ = nullptr;
std::unique_ptr<xe::threading::Semaphore> driver_semaphore_ = {};
xe::xe_fast_mutex driver_mutex_ = {};

bool SetupDriver(uint32_t sample_rate, uint32_t channels);
void DeleteDriver();
};

} // namespace apu
} // namespace xe

#endif
8 changes: 4 additions & 4 deletions src/xenia/apu/audio_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ class XmaDecoder;

class AudioSystem {
public:
// TODO(gibbed): respect XAUDIO2_MAX_QUEUED_BUFFERS somehow (ie min(64,
// XAUDIO2_MAX_QUEUED_BUFFERS))
static const size_t kMaximumQueuedFrames = 64;

virtual ~AudioSystem();

Memory* memory() const { return memory_; }
Expand Down Expand Up @@ -68,10 +72,6 @@ class AudioSystem {
AudioDriver** out_driver) = 0;
virtual void DestroyDriver(AudioDriver* driver) = 0;

// TODO(gibbed): respect XAUDIO2_MAX_QUEUED_BUFFERS somehow (ie min(64,
// XAUDIO2_MAX_QUEUED_BUFFERS))
static const size_t kMaximumQueuedFrames = 64;

Memory* memory_ = nullptr;
cpu::Processor* processor_ = nullptr;
std::unique_ptr<XmaDecoder> xma_decoder_;
Expand Down
1 change: 1 addition & 0 deletions src/xenia/apu/premake5.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ project("xenia-apu")
links({
"libavcodec",
"libavutil",
"libavformat",
"xenia-base",
})
defines({
Expand Down
5 changes: 5 additions & 0 deletions src/xenia/emulator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ Emulator::Emulator(const std::filesystem::path& command_line,
display_window_(nullptr),
memory_(),
audio_system_(),
audio_media_player_(),
graphics_system_(),
input_system_(),
export_resolver_(),
Expand Down Expand Up @@ -163,6 +164,7 @@ Emulator::~Emulator() {
input_system_.reset();
graphics_system_.reset();
audio_system_.reset();
audio_media_player_.reset();

kernel_state_.reset();
file_system_.reset();
Expand Down Expand Up @@ -298,6 +300,9 @@ X_STATUS Emulator::Setup(
if (result) {
return result;
}
audio_media_player_ = std::make_unique<apu::AudioMediaPlayer>(
audio_system_.get(), kernel_state_.get());
audio_media_player_->Setup();
}

// Initialize emulator fallback exception handling last.
Expand Down
7 changes: 7 additions & 0 deletions src/xenia/emulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <string>
#include <vector>

#include "xenia/apu/audio_media_player.h"
#include "xenia/base/delegate.h"
#include "xenia/base/exception_handler.h"
#include "xenia/kernel/kernel_state.h"
Expand Down Expand Up @@ -141,6 +142,11 @@ class Emulator {
// Audio hardware emulation for decoding and playback.
apu::AudioSystem* audio_system() const { return audio_system_.get(); }

// Xbox media player (XMP) emulation for WMA and MP3 playback.
apu::AudioMediaPlayer* audio_media_player() const {
return audio_media_player_.get();
}

// GPU emulation for command list processing.
gpu::GraphicsSystem* graphics_system() const {
return graphics_system_.get();
Expand Down Expand Up @@ -301,6 +307,7 @@ class Emulator {

std::unique_ptr<cpu::Processor> processor_;
std::unique_ptr<apu::AudioSystem> audio_system_;
std::unique_ptr<apu::AudioMediaPlayer> audio_media_player_;
std::unique_ptr<gpu::GraphicsSystem> graphics_system_;
std::unique_ptr<hid::InputSystem> input_system_;

Expand Down
6 changes: 0 additions & 6 deletions src/xenia/kernel/premake5.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,9 @@ project("xenia-kernel")
"xenia-cpu",
"xenia-hid",
"xenia-vfs",
"libavcodec",
"libavformat",
"libavutil",
})
defines({
})
includedirs({
project_root.."/third_party/FFmpeg/",
})
recursive_platform_files()
files({
"debug_visualizers.natvis",
Expand Down
Loading

0 comments on commit e500338

Please sign in to comment.