diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 1af3f5da95..2da136ede4 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "Log.h" +#include "rpcs3/Ini.h" #include "Emu/System.h" #include "Emu/CPU/CPUThread.h" #include "Emu/SysCalls/SysCalls.h" @@ -285,7 +286,7 @@ void signal_handler(int sig, siginfo_t* info, void* uct) ucontext_t* const ctx = (ucontext_t*)uct; const u64 addr64 = (u64)info->si_addr - (u64)Memory.GetBaseAddr(); //const bool is_writing = false; // TODO: get it correctly - if (addr64 < 0x100000000ull) + if (addr64 < 0x100000000ull && GetCurrentNamedThread()) { const u32 addr = (u32)addr64; if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) // RawSPU MMIO registers @@ -384,7 +385,7 @@ NamedThreadBase* GetCurrentNamedThread() void SetCurrentNamedThread(NamedThreadBase* value) { - auto old_value = g_tls_this_thread; + const auto old_value = g_tls_this_thread; if (old_value == value) { @@ -536,23 +537,40 @@ bool ThreadBase::TestDestroy() const return m_destroy; } -thread::thread(const std::string& name, std::function func) : m_name(name) +thread_t::thread_t(const std::string& name, std::function func) : m_name(name), m_state(TS_NON_EXISTENT) { start(func); } -thread::thread(const std::string& name) : m_name(name) +thread_t::thread_t(const std::string& name) : m_name(name), m_state(TS_NON_EXISTENT) { } -thread::thread() +thread_t::thread_t() : m_state(TS_NON_EXISTENT) { } -void thread::start(std::function func) +void thread_t::set_name(const std::string& name) { + m_name = name; +} + +thread_t::~thread_t() +{ + if (m_state == TS_JOINABLE) + { + m_thr.detach(); + } +} + +void thread_t::start(std::function func) +{ + if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE) + { + m_thr.join(); // forcefully join previously created thread + } + std::string name = m_name; - m_thr = std::thread([func, name]() { SetCurrentThreadDebugName(name.c_str()); @@ -567,6 +585,11 @@ void thread::start(std::function func) SetCurrentNamedThread(&info); g_thread_count++; + if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(HLE, name + " started"); + } + try { func(); @@ -580,6 +603,15 @@ void thread::start(std::function func) LOG_ERROR(GENERAL, "%s: %s", name.c_str(), e.c_str()); } + if (Emu.IsStopped()) + { + LOG_NOTICE(HLE, name + " aborted"); + } + else if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(HLE, name + " ended"); + } + SetCurrentNamedThread(nullptr); g_thread_count--; @@ -587,21 +619,41 @@ void thread::start(std::function func) _set_se_translator(old_se_translator); #endif }); + + if (m_state.exchange(TS_JOINABLE) == TS_JOINABLE) + { + assert(!"thread_t::start() failed"); // probably started from another thread + } } -void thread::detach() +void thread_t::detach() { - m_thr.detach(); + if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE) + { + m_thr.detach(); + } + else + { + assert(!"thread_t::detach() failed"); // probably joined or detached + } } -void thread::join() +void thread_t::join() { - m_thr.join(); + if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE) + { + m_thr.join(); + } + else + { + assert(!"thread_t::join() failed"); // probably joined or detached + } } -bool thread::joinable() const +bool thread_t::joinable() const { - return m_thr.joinable(); + //return m_thr.joinable(); + return m_state == TS_JOINABLE; } bool waiter_map_t::is_stopped(u64 signal_id) diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 4b54317bec..200b54b02d 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -54,18 +54,32 @@ public: virtual void Task() = 0; }; -class thread +class thread_t { + enum thread_state_t + { + TS_NON_EXISTENT, + TS_JOINABLE, + }; + + std::atomic m_state; std::string m_name; std::thread m_thr; public: - thread(const std::string& name, std::function func); - thread(const std::string& name); - thread(); + thread_t(const std::string& name, std::function func); + thread_t(const std::string& name); + thread_t(); + ~thread_t(); + thread_t(const thread_t& right) = delete; + thread_t(thread_t&& right) = delete; + + thread_t& operator =(const thread_t& right) = delete; + thread_t& operator =(thread_t&& right) = delete; public: + void set_name(const std::string& name); void start(std::function func); void detach(); void join(); diff --git a/rpcs3/Emu/Audio/AL/OpenALThread.cpp b/rpcs3/Emu/Audio/AL/OpenALThread.cpp index f63fda6dc6..38e1be699e 100644 --- a/rpcs3/Emu/Audio/AL/OpenALThread.cpp +++ b/rpcs3/Emu/Audio/AL/OpenALThread.cpp @@ -11,8 +11,6 @@ ALCenum g_last_alc_error = ALC_NO_ERROR; #define checkForAlError(sit) if((g_last_al_error = alGetError()) != AL_NO_ERROR) printAlError(g_last_al_error, sit) #define checkForAlcError(sit) if((g_last_alc_error = alcGetError(m_device)) != ALC_NO_ERROR) printAlcError(g_last_alc_error, sit) -static const ALenum g_audio_format = Ini.AudioConvertToU16.GetValue() ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32; - void printAlError(ALenum err, const char* situation) { if (err != AL_NO_ERROR) @@ -102,7 +100,7 @@ void OpenALThread::Open(const void* src, int size) for (uint i = 0; iCreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO); diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index b990e0097b..df64539f20 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -280,6 +280,7 @@ void CPUThread::Task() return "unknown function"; } + case CPU_THREAD_PPU: { if ((u32)syscall == syscall) @@ -290,6 +291,7 @@ void CPUThread::Task() { // TODO: //return SysCalls::GetSyscallName((u32)syscall); + return "unknown syscall"; } else { @@ -302,13 +304,19 @@ void CPUThread::Task() } } - // fallthrough + return "unknown function"; } + case CPU_THREAD_SPU: case CPU_THREAD_RAW_SPU: default: { - return "unknown syscall"; + if (!syscall) + { + return{}; + } + + return "unknown function"; } } }; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 28333b1e59..f3bd2be3a6 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -2350,7 +2350,7 @@ void RSXThread::Task() m_last_flip_time = get_system_time() - 1000000; volatile bool is_vblank_stopped = false; - thread vblank("VBlank thread", [&]() + thread_t vblank("VBlank thread", [&]() { const u64 start_time = get_system_time(); diff --git a/rpcs3/Emu/SysCalls/Callback.cpp b/rpcs3/Emu/SysCalls/Callback.cpp index e01b341fbe..c74fc84871 100644 --- a/rpcs3/Emu/SysCalls/Callback.cpp +++ b/rpcs3/Emu/SysCalls/Callback.cpp @@ -82,7 +82,7 @@ void CallbackManager::Init() static_cast(m_cb_thread)->DoRun(); } - thread cb_async_thread("CallbackManager::Async() thread", [this]() + thread_t cb_async_thread("CallbackManager thread", [this]() { SetCurrentNamedThread(m_cb_thread); @@ -108,8 +108,6 @@ void CallbackManager::Init() m_cb_thread->WaitForAnySignal(); } }); - - cb_async_thread.detach(); } void CallbackManager::Clear() diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index fe7c74d1a7..f1b9ef1f5e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -224,7 +224,7 @@ u32 adecOpen(AudioDecoder* adec_ptr) adec.id = adec_id; adec.adecCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); - adec.adecCb->SetName("Audio Decoder[" + std::to_string(adec_id) + "] Callback"); + adec.adecCb->SetName(fmt::format("AudioDecoder[%d] Callback", adec_id)); adec.adecCb->SetEntry(0); adec.adecCb->SetPrio(1001); adec.adecCb->SetStackSize(0x10000); @@ -232,11 +232,9 @@ u32 adecOpen(AudioDecoder* adec_ptr) adec.adecCb->InitRegs(); adec.adecCb->DoRun(); - thread t("Audio Decoder[" + std::to_string(adec_id) + "] Thread", [adec_ptr, sptr]() + thread_t t(fmt::format("AudioDecoder[%d] Thread", adec_id), [adec_ptr, sptr]() { AudioDecoder& adec = *adec_ptr; - cellAdec->Notice("Audio Decoder thread started"); - AdecTask& task = adec.task; while (true) @@ -471,18 +469,15 @@ u32 adecOpen(AudioDecoder* adec_ptr) default: { - ADEC_ERROR("Audio Decoder thread error: unknown task(%d)", task.type); + ADEC_ERROR("AudioDecoder thread error: unknown task(%d)", task.type); } } } adec.is_finished = true; - if (adec.is_closed) cellAdec->Notice("Audio Decoder thread ended"); - if (Emu.IsStopped()) cellAdec->Warning("Audio Decoder thread aborted"); + if (Emu.IsStopped()) cellAdec->Warning("AudioDecoder thread aborted"); }); - t.detach(); - return adec_id; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index 6ebbce0d14..db77b18b28 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -11,461 +11,401 @@ #include "Emu/Event.h" #include "Emu/Audio/AudioManager.h" #include "Emu/Audio/AudioDumper.h" -#include "Emu/Audio/cellAudio.h" + +#include "cellAudio.h" Module *cellAudio = nullptr; -static std::mutex audioMutex; +AudioConfig g_audio; -AudioConfig m_config; - -static const bool g_is_u16 = Ini.AudioConvertToU16.GetValue(); - -// libaudio Functions - -#define BUFFER_NUM 32 -#define BUFFER_SIZE 256 int cellAudioInit() { cellAudio->Warning("cellAudioInit()"); - if (m_config.m_is_audio_initialized) + if (!g_audio.state.compare_and_swap_test(AUDIO_STATE_NOT_INITIALIZED, AUDIO_STATE_INITIALIZED)) { return CELL_AUDIO_ERROR_ALREADY_INIT; } - m_config.m_is_audio_initialized = true; - m_config.start_time = 0; - m_config.counter = 0; + for (auto& port : g_audio.ports) + { + port.state.write_relaxed(AUDIO_PORT_STATE_NOT_OPENED); + } - // alloc memory - m_config.m_buffer = (u32)Memory.Alloc(128 * 1024 * m_config.AUDIO_PORT_COUNT, 1024); - memset(vm::get_ptr(m_config.m_buffer), 0, 128 * 1024 * m_config.AUDIO_PORT_COUNT); - m_config.m_indexes = (u32)Memory.Alloc(sizeof(u64) * m_config.AUDIO_PORT_COUNT, 16); - memset(vm::get_ptr(m_config.m_indexes), 0, sizeof(u64) * m_config.AUDIO_PORT_COUNT); + g_audio.start_time = 0; + g_audio.counter = 0; + g_audio.keys.clear(); - thread t("Audio Thread", []() + // alloc memory (only once until the emulator is stopped) + g_audio.buffer = g_audio.buffer ? g_audio.buffer : vm::cast(Memory.MainMem.AllocAlign(128 * 1024 * AUDIO_PORT_COUNT, 4096)); + g_audio.indexes = g_audio.indexes ? g_audio.indexes : vm::cast(Memory.MainMem.AllocAlign(sizeof(u64) * AUDIO_PORT_COUNT, __alignof(u64))); + + // clear memory + memset(vm::get_ptr(g_audio.buffer), 0, 128 * 1024 * AUDIO_PORT_COUNT); + memset(vm::get_ptr(g_audio.indexes), 0, sizeof(u64) * AUDIO_PORT_COUNT); + + g_audio.audio_thread.start([]() + { + const bool do_dump = Ini.AudioDumpToFile.GetValue(); + + AudioDumper m_dump; + if (do_dump && !m_dump.Init(8)) // Init AudioDumper for 8 channels { - AudioDumper m_dump(8); // WAV file header (8 ch) + cellAudio->Error("AudioDumper::Init() failed"); + return; + } - bool do_dump = Ini.AudioDumpToFile.GetValue(); - - if (do_dump && !m_dump.Init()) - { - cellAudio->Error("cellAudioInit(): AudioDumper::Init() failed"); - return; - } + float buf2ch[2 * BUFFER_SIZE]; // intermediate buffer for 2 channels + float buf8ch[8 * BUFFER_SIZE]; // intermediate buffer for 8 channels - cellAudio->Notice("Audio thread started"); + static const size_t out_buffer_size = 2 * BUFFER_SIZE; - if (Ini.AudioDumpToFile.GetValue()) - m_dump.WriteHeader(); + std::unique_ptr out_buffer[BUFFER_NUM]; - float buf2ch[2 * BUFFER_SIZE]; // intermediate buffer for 2 channels - float buf8ch[8 * BUFFER_SIZE]; // intermediate buffer for 8 channels + for (u32 i = 0; i < BUFFER_NUM; i++) + { + out_buffer[i].reset(new float[2 * BUFFER_SIZE] {}); + } - uint oal_buffer_offset = 0; - const uint oal_buffer_size = 2 * BUFFER_SIZE; + squeue_t out_queue; - std::unique_ptr oal_buffer[BUFFER_NUM]; - std::unique_ptr oal_buffer_float[BUFFER_NUM]; + std::vector keys; - for (u32 i = 0; i < BUFFER_NUM; i++) - { - oal_buffer[i] = std::unique_ptr(new s16[oal_buffer_size] {} ); - oal_buffer_float[i] = std::unique_ptr(new float[oal_buffer_size] {} ); - } + g_audio.start_time = get_system_time(); - squeue_t queue; - squeue_t queue_float; - - std::vector keys; + thread_t iat("Internal Audio Thread", [&out_queue]() + { + const bool use_u16 = Ini.AudioConvertToU16.GetValue(); Emu.GetAudioManager().GetAudioOut().Init(); - // Note: What if the ini value changes? - if (g_is_u16) - Emu.GetAudioManager().GetAudioOut().Open(oal_buffer[0].get(), oal_buffer_size * sizeof(s16)); - else - Emu.GetAudioManager().GetAudioOut().Open(oal_buffer_float[0].get(), oal_buffer_size * sizeof(float)); - + bool opened = false; - m_config.start_time = get_system_time(); - - volatile bool internal_finished = false; - - thread iat("Internal Audio Thread", [oal_buffer_size, &queue, &queue_float, &internal_finished]() + while (g_audio.state.read_relaxed() == AUDIO_STATE_INITIALIZED && !Emu.IsStopped()) { - while (true) + float* buffer; + if (out_queue.pop(buffer)) { - s16* oal_buffer = nullptr; - float* oal_buffer_float = nullptr; - - if (g_is_u16) - queue.pop(oal_buffer); - else - queue_float.pop(oal_buffer_float); - - if (g_is_u16) + if (use_u16) { - if (oal_buffer) - { - Emu.GetAudioManager().GetAudioOut().AddData(oal_buffer, oal_buffer_size * sizeof(s16)); - continue; - } - } - else - { - if (oal_buffer_float) - { - Emu.GetAudioManager().GetAudioOut().AddData(oal_buffer_float, oal_buffer_size * sizeof(float)); - continue; - } - } - internal_finished = true; - return; - } - }); - iat.detach(); + // convert the data from float to u16 with clipping: + // 2x MULPS + // 2x MAXPS (optional) + // 2x MINPS (optional) + // 2x CVTPS2DQ (converts float to s32) + // PACKSSDW (converts s32 to s16 with signed saturation) - while (m_config.m_is_audio_initialized) - { - if (Emu.IsStopped()) - { - cellAudio->Warning("Audio thread aborted"); - goto abort; - } - - const u64 stamp0 = get_system_time(); - - // TODO: send beforemix event (in ~2,6 ms before mixing) - - // precise time of sleeping: 5,(3) ms (or 256/48000 sec) - if (m_config.counter * 256000000 / 48000 >= stamp0 - m_config.start_time) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - - m_config.counter++; - - const u32 oal_pos = m_config.counter % BUFFER_NUM; - - if (Emu.IsPaused()) - { - continue; - } - - bool first_mix = true; - - // mixing: - for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++) - { - if (!m_config.m_ports[i].m_is_audio_port_started) continue; - - AudioPortConfig& port = m_config.m_ports[i]; - - const u32 block_size = port.channel * 256; - const u32 position = port.tag % port.block; // old value - const u32 buf_addr = m_config.m_buffer + (i * 128 * 1024) + (position * block_size * sizeof(float)); - - auto buf = vm::get_ptr>(buf_addr); - - static const float k = 1.0f; // may be 1.0f - const float m = port.level; - - if (port.channel == 2) - { - if (first_mix) - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - // reverse byte order - const float left = buf[i + 0] * m; - const float right = buf[i + 1] * m; - - buf2ch[i + 0] = left; - buf2ch[i + 1] = right; - - buf8ch[i * 4 + 0] = left; - buf8ch[i * 4 + 1] = right; - buf8ch[i * 4 + 2] = 0.0f; - buf8ch[i * 4 + 3] = 0.0f; - buf8ch[i * 4 + 4] = 0.0f; - buf8ch[i * 4 + 5] = 0.0f; - buf8ch[i * 4 + 6] = 0.0f; - buf8ch[i * 4 + 7] = 0.0f; - } - first_mix = false; - } - else - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i + 0] * m; - const float right = buf[i + 1] * m; - - buf2ch[i + 0] += left; - buf2ch[i + 1] += right; - - buf8ch[i * 4 + 0] += left; - buf8ch[i * 4 + 1] += right; - } - } - } - else if (port.channel == 6) - { - if (first_mix) - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i * 3 + 0] * m; - const float right = buf[i * 3 + 1] * m; - const float center = buf[i * 3 + 2] * m; - const float low_freq = buf[i * 3 + 3] * m; - const float rear_left = buf[i * 3 + 4] * m; - const float rear_right = buf[i * 3 + 5] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] = (left + rear_left + mid) * k; - buf2ch[i + 1] = (right + rear_right + mid) * k; - - buf8ch[i * 4 + 0] = left; - buf8ch[i * 4 + 1] = right; - buf8ch[i * 4 + 2] = center; - buf8ch[i * 4 + 3] = low_freq; - buf8ch[i * 4 + 4] = rear_left; - buf8ch[i * 4 + 5] = rear_right; - buf8ch[i * 4 + 6] = 0.0f; - buf8ch[i * 4 + 7] = 0.0f; - } - first_mix = false; - } - else - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i * 3 + 0] * m; - const float right = buf[i * 3 + 1] * m; - const float center = buf[i * 3 + 2] * m; - const float low_freq = buf[i * 3 + 3] * m; - const float rear_left = buf[i * 3 + 4] * m; - const float rear_right = buf[i * 3 + 5] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] += (left + rear_left + mid) * k; - buf2ch[i + 1] += (right + rear_right + mid) * k; - - buf8ch[i * 4 + 0] += left; - buf8ch[i * 4 + 1] += right; - buf8ch[i * 4 + 2] += center; - buf8ch[i * 4 + 3] += low_freq; - buf8ch[i * 4 + 4] += rear_left; - buf8ch[i * 4 + 5] += rear_right; - } - } - } - else if (port.channel == 8) - { - if (first_mix) - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i * 4 + 0] * m; - const float right = buf[i * 4 + 1] * m; - const float center = buf[i * 4 + 2] * m; - const float low_freq = buf[i * 4 + 3] * m; - const float rear_left = buf[i * 4 + 4] * m; - const float rear_right = buf[i * 4 + 5] * m; - const float side_left = buf[i * 4 + 6] * m; - const float side_right = buf[i * 4 + 7] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] = (left + rear_left + side_left + mid) * k; - buf2ch[i + 1] = (right + rear_right + side_right + mid) * k; - - buf8ch[i * 4 + 0] = left; - buf8ch[i * 4 + 1] = right; - buf8ch[i * 4 + 2] = center; - buf8ch[i * 4 + 3] = low_freq; - buf8ch[i * 4 + 4] = rear_left; - buf8ch[i * 4 + 5] = rear_right; - buf8ch[i * 4 + 6] = side_left; - buf8ch[i * 4 + 7] = side_right; - } - first_mix = false; - } - else - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i * 4 + 0] * m; - const float right = buf[i * 4 + 1] * m; - const float center = buf[i * 4 + 2] * m; - const float low_freq = buf[i * 4 + 3] * m; - const float rear_left = buf[i * 4 + 4] * m; - const float rear_right = buf[i * 4 + 5] * m; - const float side_left = buf[i * 4 + 6] * m; - const float side_right = buf[i * 4 + 7] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] += (left + rear_left + side_left + mid) * k; - buf2ch[i + 1] += (right + rear_right + side_right + mid) * k; - - buf8ch[i * 4 + 0] += left; - buf8ch[i * 4 + 1] += right; - buf8ch[i * 4 + 2] += center; - buf8ch[i * 4 + 3] += low_freq; - buf8ch[i * 4 + 4] += rear_left; - buf8ch[i * 4 + 5] += rear_right; - buf8ch[i * 4 + 6] += side_left; - buf8ch[i * 4 + 7] += side_right; - } - } - } - - memset(buf, 0, block_size * sizeof(float)); - } - - // convert the data from float to u16 with clipping: - if (!first_mix) - { - // 2x MULPS - // 2x MAXPS (optional) - // 2x MINPS (optional) - // 2x CVTPS2DQ (converts float to s32) - // PACKSSDW (converts s32 to s16 with signed saturation) - - if (g_is_u16) - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 8) + u16 buf_u16[out_buffer_size]; + for (size_t i = 0; i < out_buffer_size; i += 8) { static const __m128 float2u16 = { 0x8000, 0x8000, 0x8000, 0x8000 }; - (__m128i&)(oal_buffer[oal_pos][oal_buffer_offset + i]) = _mm_packs_epi32( - _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buf2ch[i]), float2u16)), - _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buf2ch[i + 4]), float2u16))); + (__m128i&)(buf_u16[i]) = _mm_packs_epi32( + _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buffer[i]), float2u16)), + _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buffer[i + 4]), float2u16))); } - } - else - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++) - { - oal_buffer_float[oal_pos][oal_buffer_offset + i] = buf2ch[i]; - } - } - //const u64 stamp1 = get_system_time(); - - if (first_mix) - { - if (g_is_u16) memset(&oal_buffer[oal_pos][0], 0, oal_buffer_size * sizeof(s16)); - else memset(&oal_buffer_float[oal_pos][0], 0, oal_buffer_size * sizeof(float)); - } - oal_buffer_offset += sizeof(buf2ch) / sizeof(float); - - if(oal_buffer_offset >= oal_buffer_size) - { - if (g_is_u16) - queue.push(&oal_buffer[oal_pos][0]); - - queue_float.push(&oal_buffer_float[oal_pos][0]); - oal_buffer_offset = 0; - } - - //const u64 stamp2 = get_system_time(); - - // send aftermix event (normal audio event) - { - std::lock_guard lock(audioMutex); - // update indexes: - auto indexes = vm::ptr::make(m_config.m_indexes); - for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++) - { - if (!m_config.m_ports[i].m_is_audio_port_started) continue; - - AudioPortConfig& port = m_config.m_ports[i]; - - u32 position = port.tag % port.block; // old value - port.counter = m_config.counter; - port.tag++; // absolute index of block that will be read - indexes[i] = (position + 1) % port.block; // write new value - } - // load keys: - keys.resize(m_config.m_keys.size()); - memcpy(keys.data(), m_config.m_keys.data(), sizeof(u64) * keys.size()); - } - for (u32 i = 0; i < keys.size(); i++) - { - // TODO: check event source - Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0); - } - - //const u64 stamp3 = get_system_time(); - - if (do_dump && !first_mix) - { - if (m_dump.GetCh() == 8) - { - if (m_dump.WriteData(&buf8ch, sizeof(buf8ch)) != sizeof(buf8ch)) // write file data + if (!opened) { - cellAudio->Error("cellAudioInit(): AudioDumper::WriteData() failed"); - goto abort; + Emu.GetAudioManager().GetAudioOut().Open(buf_u16, out_buffer_size * sizeof(u16)); + opened = true; } - } - else if (m_dump.GetCh() == 2) - { - if (m_dump.WriteData(&buf2ch, sizeof(buf2ch)) != sizeof(buf2ch)) // write file data + else { - cellAudio->Error("cellAudioInit(): AudioDumper::WriteData() failed"); - goto abort; + Emu.GetAudioManager().GetAudioOut().AddData(buf_u16, out_buffer_size * sizeof(u16)); } } else { - cellAudio->Error("cellAudioInit(): unknown AudioDumper::GetCh() value (%d)", m_dump.GetCh()); - goto abort; + if (!opened) + { + Emu.GetAudioManager().GetAudioOut().Open(buffer, out_buffer_size * sizeof(float)); + opened = true; + } + else + { + Emu.GetAudioManager().GetAudioOut().AddData(buffer, out_buffer_size * sizeof(float)); + } } } - - //LOG_NOTICE(HLE, "Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)", - //stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); - } - cellAudio->Notice("Audio thread ended"); -abort: - queue.push(nullptr); - queue_float.push(nullptr); - - if(do_dump) - m_dump.Finalize(); - - m_config.m_is_audio_initialized = false; - - m_config.m_keys.clear(); - for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++) - { - AudioPortConfig& port = m_config.m_ports[i]; - port.m_is_audio_port_opened = false; - port.m_is_audio_port_started = false; - } - m_config.m_port_in_use = 0; - - while (!internal_finished) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + else + { + break; + } } - m_config.m_is_audio_finalized = true; + Emu.GetAudioManager().GetAudioOut().Quit(); }); - t.detach(); - while (!m_config.start_time) // waiting for initialization - { - if (Emu.IsStopped()) + while (g_audio.state.read_relaxed() == AUDIO_STATE_INITIALIZED && !Emu.IsStopped()) { - cellAudio->Warning("cellAudioInit() aborted"); - return CELL_OK; + const u64 stamp0 = get_system_time(); + + // TODO: send beforemix event (in ~2,6 ms before mixing) + + // precise time of sleeping: 5,(3) ms (or 256/48000 sec) + if (g_audio.counter * 256000000 / 48000 >= stamp0 - g_audio.start_time) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + } + + g_audio.counter++; + + const u32 out_pos = g_audio.counter % BUFFER_NUM; + + if (Emu.IsPaused()) + { + continue; + } + + bool first_mix = true; + + // mixing: + for (auto& port : g_audio.ports) + { + if (port.state.read_relaxed() != AUDIO_PORT_STATE_STARTED) continue; + + const u32 block_size = port.channel * 256; + const u32 position = port.tag % port.block; // old value + const u32 buf_addr = port.addr + position * block_size * sizeof(float); + + auto buf = vm::get_ptr>(buf_addr); + + static const float k = 1.0f; // may be 1.0f + const float m = port.level; + + if (port.channel == 2) + { + if (first_mix) + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + // reverse byte order + const float left = buf[i + 0] * m; + const float right = buf[i + 1] * m; + + buf2ch[i + 0] = left; + buf2ch[i + 1] = right; + + buf8ch[i * 4 + 0] = left; + buf8ch[i * 4 + 1] = right; + buf8ch[i * 4 + 2] = 0.0f; + buf8ch[i * 4 + 3] = 0.0f; + buf8ch[i * 4 + 4] = 0.0f; + buf8ch[i * 4 + 5] = 0.0f; + buf8ch[i * 4 + 6] = 0.0f; + buf8ch[i * 4 + 7] = 0.0f; + } + first_mix = false; + } + else + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + const float left = buf[i + 0] * m; + const float right = buf[i + 1] * m; + + buf2ch[i + 0] += left; + buf2ch[i + 1] += right; + + buf8ch[i * 4 + 0] += left; + buf8ch[i * 4 + 1] += right; + } + } + } + else if (port.channel == 6) + { + if (first_mix) + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + const float left = buf[i * 3 + 0] * m; + const float right = buf[i * 3 + 1] * m; + const float center = buf[i * 3 + 2] * m; + const float low_freq = buf[i * 3 + 3] * m; + const float rear_left = buf[i * 3 + 4] * m; + const float rear_right = buf[i * 3 + 5] * m; + + const float mid = (center + low_freq) * 0.708f; + buf2ch[i + 0] = (left + rear_left + mid) * k; + buf2ch[i + 1] = (right + rear_right + mid) * k; + + buf8ch[i * 4 + 0] = left; + buf8ch[i * 4 + 1] = right; + buf8ch[i * 4 + 2] = center; + buf8ch[i * 4 + 3] = low_freq; + buf8ch[i * 4 + 4] = rear_left; + buf8ch[i * 4 + 5] = rear_right; + buf8ch[i * 4 + 6] = 0.0f; + buf8ch[i * 4 + 7] = 0.0f; + } + first_mix = false; + } + else + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + const float left = buf[i * 3 + 0] * m; + const float right = buf[i * 3 + 1] * m; + const float center = buf[i * 3 + 2] * m; + const float low_freq = buf[i * 3 + 3] * m; + const float rear_left = buf[i * 3 + 4] * m; + const float rear_right = buf[i * 3 + 5] * m; + + const float mid = (center + low_freq) * 0.708f; + buf2ch[i + 0] += (left + rear_left + mid) * k; + buf2ch[i + 1] += (right + rear_right + mid) * k; + + buf8ch[i * 4 + 0] += left; + buf8ch[i * 4 + 1] += right; + buf8ch[i * 4 + 2] += center; + buf8ch[i * 4 + 3] += low_freq; + buf8ch[i * 4 + 4] += rear_left; + buf8ch[i * 4 + 5] += rear_right; + } + } + } + else if (port.channel == 8) + { + if (first_mix) + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + const float left = buf[i * 4 + 0] * m; + const float right = buf[i * 4 + 1] * m; + const float center = buf[i * 4 + 2] * m; + const float low_freq = buf[i * 4 + 3] * m; + const float rear_left = buf[i * 4 + 4] * m; + const float rear_right = buf[i * 4 + 5] * m; + const float side_left = buf[i * 4 + 6] * m; + const float side_right = buf[i * 4 + 7] * m; + + const float mid = (center + low_freq) * 0.708f; + buf2ch[i + 0] = (left + rear_left + side_left + mid) * k; + buf2ch[i + 1] = (right + rear_right + side_right + mid) * k; + + buf8ch[i * 4 + 0] = left; + buf8ch[i * 4 + 1] = right; + buf8ch[i * 4 + 2] = center; + buf8ch[i * 4 + 3] = low_freq; + buf8ch[i * 4 + 4] = rear_left; + buf8ch[i * 4 + 5] = rear_right; + buf8ch[i * 4 + 6] = side_left; + buf8ch[i * 4 + 7] = side_right; + } + first_mix = false; + } + else + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + const float left = buf[i * 4 + 0] * m; + const float right = buf[i * 4 + 1] * m; + const float center = buf[i * 4 + 2] * m; + const float low_freq = buf[i * 4 + 3] * m; + const float rear_left = buf[i * 4 + 4] * m; + const float rear_right = buf[i * 4 + 5] * m; + const float side_left = buf[i * 4 + 6] * m; + const float side_right = buf[i * 4 + 7] * m; + + const float mid = (center + low_freq) * 0.708f; + buf2ch[i + 0] += (left + rear_left + side_left + mid) * k; + buf2ch[i + 1] += (right + rear_right + side_right + mid) * k; + + buf8ch[i * 4 + 0] += left; + buf8ch[i * 4 + 1] += right; + buf8ch[i * 4 + 2] += center; + buf8ch[i * 4 + 3] += low_freq; + buf8ch[i * 4 + 4] += rear_left; + buf8ch[i * 4 + 5] += rear_right; + buf8ch[i * 4 + 6] += side_left; + buf8ch[i * 4 + 7] += side_right; + } + } + } + + memset(buf, 0, block_size * sizeof(float)); + } + + + if (!first_mix) + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++) + { + out_buffer[out_pos][i] = buf2ch[i]; + } + } + + //const u64 stamp1 = get_system_time(); + + if (first_mix) + { + memset(out_buffer[out_pos].get(), 0, out_buffer_size * sizeof(float)); + } + + out_queue.push(out_buffer[out_pos].get()); + + //const u64 stamp2 = get_system_time(); + + // send aftermix event (normal audio event) + { + std::lock_guard lock(g_audio.mutex); + // update indexes: + auto indexes = vm::ptr::make(g_audio.indexes); + for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) + { + AudioPortConfig& port = g_audio.ports[i]; + + if (port.state.read_relaxed() != AUDIO_PORT_STATE_STARTED) continue; + + u32 position = port.tag % port.block; // old value + port.counter = g_audio.counter; + port.tag++; // absolute index of block that will be read + indexes[i] = (position + 1) % port.block; // write new value + } + // load keys: + keys.resize(g_audio.keys.size()); + memcpy(keys.data(), g_audio.keys.data(), sizeof(u64) * keys.size()); + } + for (u32 i = 0; i < keys.size(); i++) + { + // TODO: check event source + Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0); + } + + //const u64 stamp3 = get_system_time(); + + if (do_dump && !first_mix) + { + if (m_dump.GetCh() == 8) + { + if (m_dump.WriteData(&buf8ch, sizeof(buf8ch)) != sizeof(buf8ch)) // write file data + { + cellAudio->Error("AudioDumper::WriteData() failed"); + break; + } + } + else if (m_dump.GetCh() == 2) + { + if (m_dump.WriteData(&buf2ch, sizeof(buf2ch)) != sizeof(buf2ch)) // write file data + { + cellAudio->Error("AudioDumper::WriteData() failed"); + break; + } + } + else + { + cellAudio->Error("AudioDumper::GetCh() returned unknown value (%d)", m_dump.GetCh()); + break; + } + } + + //LOG_NOTICE(HLE, "Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)", + //stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - } + + iat.join(); + }); return CELL_OK; } @@ -474,26 +414,13 @@ int cellAudioQuit() { cellAudio->Warning("cellAudioQuit()"); - if (!m_config.m_is_audio_initialized) + if (!g_audio.state.compare_and_swap_test(AUDIO_STATE_INITIALIZED, AUDIO_STATE_FINALIZED)) { return CELL_AUDIO_ERROR_NOT_INIT; } - m_config.m_is_audio_initialized = false; - - while (!m_config.m_is_audio_finalized) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - if (Emu.IsStopped()) - { - cellAudio->Warning("cellAudioQuit(): aborted"); - return CELL_OK; - } - } - - Memory.Free(m_config.m_buffer); - Memory.Free(m_config.m_indexes); - + g_audio.audio_thread.join(); + g_audio.state.exchange(AUDIO_STATE_NOT_INITIALIZED); return CELL_OK; } @@ -506,22 +433,17 @@ int cellAudioPortOpen(vm::ptr audioParam, vm::ptr portN return CELL_AUDIO_ERROR_PARAM; } - if (m_config.m_port_in_use >= m_config.AUDIO_PORT_COUNT) + for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) { - return CELL_AUDIO_ERROR_PORT_FULL; - } - - for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++) - { - if (!m_config.m_ports[i].m_is_audio_port_opened) + if (g_audio.ports[i].state.compare_and_swap_test(AUDIO_PORT_STATE_NOT_OPENED, AUDIO_PORT_STATE_OPENED)) { - AudioPortConfig& port = m_config.m_ports[i]; - + AudioPortConfig& port = g_audio.ports[i]; + port.channel = (u8)audioParam->nChannel; port.block = (u8)audioParam->nBlock; port.attr = audioParam->attr; - port.addr = m_config.m_buffer + (128 * 1024 * i); - port.read_index_addr = m_config.m_indexes + (sizeof(u64) * i); + port.addr = g_audio.buffer + (128 * 1024 * i); + port.read_index_addr = g_audio.indexes + (sizeof(u64) * i); port.size = port.channel * port.block * 256 * sizeof(float); if (port.attr & CELL_AUDIO_PORTATTR_INITLEVEL) { @@ -535,12 +457,8 @@ int cellAudioPortOpen(vm::ptr audioParam, vm::ptr portN *portNum = i; cellAudio->Warning("*** audio port opened(nChannel=%d, nBlock=%d, attr=0x%llx, level=%f): port = %d", port.channel, port.block, port.attr, port.level, i); - - port.m_is_audio_port_opened = true; - port.m_is_audio_port_started = false; - port.tag = 0; - m_config.m_port_in_use++; + port.tag = 0; return CELL_OK; } } @@ -552,25 +470,20 @@ int cellAudioGetPortConfig(u32 portNum, vm::ptr portConfig) { cellAudio->Warning("cellAudioGetPortConfig(portNum=0x%x, portConfig_addr=0x%x)", portNum, portConfig.addr()); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) + switch (auto state = g_audio.ports[portNum].state.read_sync()) { - portConfig->status = CELL_AUDIO_STATUS_CLOSE; - } - else if (m_config.m_ports[portNum].m_is_audio_port_started) - { - portConfig->status = CELL_AUDIO_STATUS_RUN; - } - else - { - portConfig->status = CELL_AUDIO_STATUS_READY; + case AUDIO_PORT_STATE_NOT_OPENED: portConfig->status = CELL_AUDIO_STATUS_CLOSE; break; + case AUDIO_PORT_STATE_OPENED: portConfig->status = CELL_AUDIO_STATUS_READY; break; + case AUDIO_PORT_STATE_STARTED: portConfig->status = CELL_AUDIO_STATUS_RUN; break; + default: throw fmt::format("cellAudioGetPortConfig(%d): invalid port state (0x%x)", portNum, state); } - AudioPortConfig& port = m_config.m_ports[portNum]; + AudioPortConfig& port = g_audio.ports[portNum]; portConfig->nChannel = port.channel; portConfig->nBlock = port.block; @@ -589,93 +502,80 @@ int cellAudioPortStart(u32 portNum) { cellAudio->Warning("cellAudioPortStart(portNum=0x%x)", portNum); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) + switch (auto state = g_audio.ports[portNum].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED)) { - return CELL_AUDIO_ERROR_PORT_OPEN; + case AUDIO_PORT_STATE_NOT_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_STARTED: return CELL_AUDIO_ERROR_PORT_ALREADY_RUN; + case AUDIO_PORT_STATE_OPENED: return CELL_OK; + default: throw fmt::format("cellAudioPortStart(%d): invalid port state (0x%x)", portNum, state); } - - if (m_config.m_ports[portNum].m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_ALREADY_RUN; - } - - m_config.m_ports[portNum].m_is_audio_port_started = true; - - return CELL_OK; } int cellAudioPortClose(u32 portNum) { cellAudio->Warning("cellAudioPortClose(portNum=0x%x)", portNum); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) + switch (auto state = g_audio.ports[portNum].state.exchange(AUDIO_PORT_STATE_NOT_OPENED)) { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_NOT_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_STARTED: return CELL_OK; + case AUDIO_PORT_STATE_OPENED: return CELL_OK; + default: throw fmt::format("cellAudioPortClose(%d): invalid port state (0x%x)", portNum, state); } - - m_config.m_ports[portNum].m_is_audio_port_started = false; - m_config.m_ports[portNum].m_is_audio_port_opened = false; - m_config.m_port_in_use--; - return CELL_OK; } int cellAudioPortStop(u32 portNum) { - cellAudio->Warning("cellAudioPortStop(portNum=0x%x)",portNum); - - if (portNum >= m_config.AUDIO_PORT_COUNT) + cellAudio->Warning("cellAudioPortStop(portNum=0x%x)", portNum); + + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) + switch (auto state = g_audio.ports[portNum].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED)) { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_NOT_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_STARTED: return CELL_OK; + case AUDIO_PORT_STATE_OPENED: return CELL_AUDIO_ERROR_PORT_OPEN; + default: throw fmt::format("cellAudioPortStop(%d): invalid port state (0x%x)", portNum, state); } - - if (!m_config.m_ports[portNum].m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; - } - - m_config.m_ports[portNum].m_is_audio_port_started = false; - return CELL_OK; } int cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr stamp) { cellAudio->Log("cellAudioGetPortTimestamp(portNum=0x%x, tag=0x%llx, stamp_addr=0x%x)", portNum, tag, stamp.addr()); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) - { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - } + //if (!g_audio.ports[portNum].is_audio_port_opened) + //{ + // return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + //} - if (!m_config.m_ports[portNum].m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; - } + //if (!g_audio.ports[portNum].is_audio_port_started) + //{ + // return CELL_AUDIO_ERROR_PORT_NOT_RUN; + //} - AudioPortConfig& port = m_config.m_ports[portNum]; + AudioPortConfig& port = g_audio.ports[portNum]; - std::lock_guard lock(audioMutex); + std::lock_guard lock(g_audio.mutex); - *stamp = m_config.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000; + *stamp = g_audio.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000; return CELL_OK; } @@ -684,22 +584,22 @@ int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr tag) { cellAudio->Log("cellAudioGetPortBlockTag(portNum=0x%x, blockNo=0x%llx, tag_addr=0x%x)", portNum, blockNo, tag.addr()); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) - { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - } + //if (!g_audio.ports[portNum].is_audio_port_opened) + //{ + // return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + //} - if (!m_config.m_ports[portNum].m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; - } + //if (!g_audio.ports[portNum].is_audio_port_started) + //{ + // return CELL_AUDIO_ERROR_PORT_NOT_RUN; + //} - AudioPortConfig& port = m_config.m_ports[portNum]; + AudioPortConfig& port = g_audio.ports[portNum]; if (blockNo >= port.block) { @@ -707,17 +607,17 @@ int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr tag) return CELL_AUDIO_ERROR_PARAM; } - std::lock_guard lock(audioMutex); + std::lock_guard lock(g_audio.mutex); u64 tag_base = port.tag; if (tag_base % port.block > blockNo) { - tag_base &= ~(port.block-1); + tag_base &= ~(port.block - 1); tag_base += port.block; } else { - tag_base &= ~(port.block-1); + tag_base &= ~(port.block - 1); } *tag = tag_base + blockNo; @@ -728,24 +628,24 @@ int cellAudioSetPortLevel(u32 portNum, float level) { cellAudio->Todo("cellAudioSetPortLevel(portNum=0x%x, level=%f)", portNum, level); - AudioPortConfig& port = m_config.m_ports[portNum]; - - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!port.m_is_audio_port_opened) - { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - } + AudioPortConfig& port = g_audio.ports[portNum]; - if (!port.m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; - } + //if (!port.is_audio_port_opened) + //{ + // return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + //} - std::lock_guard lock(audioMutex); + //if (!port.is_audio_port_started) + //{ + // return CELL_AUDIO_ERROR_PORT_NOT_RUN; + //} + + std::lock_guard lock(g_audio.mutex); port.level = level; // TODO @@ -757,7 +657,7 @@ int cellAudioCreateNotifyEventQueue(vm::ptr id, vm::ptr key) { cellAudio->Warning("cellAudioCreateNotifyEventQueue(id_addr=0x%x, key_addr=0x%x)", id.addr(), key.addr()); - std::lock_guard lock(audioMutex); + std::lock_guard lock(g_audio.mutex); u64 event_key = 0; while (Emu.GetEventManager().CheckKey((event_key << 48) | 0x80004d494f323221)) @@ -790,21 +690,21 @@ int cellAudioSetNotifyEventQueue(u64 key) { cellAudio->Warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key); - std::lock_guard lock(audioMutex); + std::lock_guard lock(g_audio.mutex); - for (u32 i = 0; i < m_config.m_keys.size(); i++) // check for duplicates + for (u32 i = 0; i < g_audio.keys.size(); i++) // check for duplicates { - if (m_config.m_keys[i] == key) + if (g_audio.keys[i] == key) { return CELL_AUDIO_ERROR_PARAM; } } - m_config.m_keys.push_back(key); + g_audio.keys.push_back(key); /*EventQueue* eq; if (!Emu.GetEventManager().GetEventQueue(key, eq)) { - return CELL_AUDIO_ERROR_PARAM; + return CELL_AUDIO_ERROR_PARAM; }*/ // TODO: connect port (?????) @@ -822,14 +722,14 @@ int cellAudioRemoveNotifyEventQueue(u64 key) { cellAudio->Warning("cellAudioRemoveNotifyEventQueue(key=0x%llx)", key); - std::lock_guard lock(audioMutex); + std::lock_guard lock(g_audio.mutex); bool found = false; - for (u32 i = 0; i < m_config.m_keys.size(); i++) + for (u32 i = 0; i < g_audio.keys.size(); i++) { - if (m_config.m_keys[i] == key) + if (g_audio.keys[i] == key) { - m_config.m_keys.erase(m_config.m_keys.begin() + i); + g_audio.keys.erase(g_audio.keys.begin() + i); found = true; break; } @@ -844,7 +744,7 @@ int cellAudioRemoveNotifyEventQueue(u64 key) /*EventQueue* eq; if (!Emu.GetEventManager().GetEventQueue(key, eq)) { - return CELL_AUDIO_ERROR_PARAM; + return CELL_AUDIO_ERROR_PARAM; }*/ // TODO: disconnect port @@ -860,14 +760,14 @@ int cellAudioRemoveNotifyEventQueueEx(u64 key, u32 iFlags) s32 cellAudioAddData(u32 portNum, vm::ptr src, u32 samples, float volume) { - cellAudio->Log("cellAudioAddData(portNum=%d, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume); - - if (!m_config.m_is_audio_initialized) + cellAudio->Log("cellAudioAddData(portNum=%d, src=0x%x, samples=%d, volume=%f)", portNum, src, samples, volume); + + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) { return CELL_AUDIO_ERROR_NOT_INIT; } - if (portNum >= m_config.AUDIO_PORT_COUNT || !src || src.addr() % 4) + if (portNum >= AUDIO_PORT_COUNT || !src || src.addr() % 4) { return CELL_AUDIO_ERROR_PARAM; } @@ -879,8 +779,8 @@ s32 cellAudioAddData(u32 portNum, vm::ptr src, u32 samples, float volume) return CELL_AUDIO_ERROR_PARAM; } - const AudioPortConfig& port = m_config.m_ports[portNum]; - + const AudioPortConfig& port = g_audio.ports[portNum]; + const auto dst = vm::ptr::make(port.addr + (port.tag % port.block) * port.channel * 256 * sizeof(float)); for (u32 i = 0; i < samples * port.channel; i++) @@ -893,19 +793,14 @@ s32 cellAudioAddData(u32 portNum, vm::ptr src, u32 samples, float volume) s32 cellAudioAdd2chData(u32 portNum, vm::ptr src, u32 samples, float volume) { - cellAudio->Log("cellAudioAdd2chData(portNum=%d, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume); + cellAudio->Log("cellAudioAdd2chData(portNum=%d, src=0x%x, samples=%d, volume=%f)", portNum, src, samples, volume); - if (!m_config.m_is_audio_initialized) + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) { return CELL_AUDIO_ERROR_NOT_INIT; } - if (portNum >= m_config.AUDIO_PORT_COUNT) - { - return CELL_AUDIO_ERROR_PARAM; - } - - if (portNum >= m_config.AUDIO_PORT_COUNT || !src || src.addr() % 4) + if (portNum >= AUDIO_PORT_COUNT || !src || src.addr() % 4) { return CELL_AUDIO_ERROR_PARAM; } @@ -917,7 +812,7 @@ s32 cellAudioAdd2chData(u32 portNum, vm::ptr src, u32 samples, float volu return CELL_AUDIO_ERROR_PARAM; } - const AudioPortConfig& port = m_config.m_ports[portNum]; + const AudioPortConfig& port = g_audio.ports[portNum]; const auto dst = vm::ptr::make(port.addr + (port.tag % port.block) * port.channel * 256 * sizeof(float)); @@ -961,24 +856,19 @@ s32 cellAudioAdd2chData(u32 portNum, vm::ptr src, u32 samples, float volu s32 cellAudioAdd6chData(u32 portNum, vm::ptr src, float volume) { - cellAudio->Log("cellAudioAdd6chData(portNum=%d, src_addr=0x%x, volume=%f)", portNum, src.addr(), volume); + cellAudio->Log("cellAudioAdd6chData(portNum=%d, src=0x%x, volume=%f)", portNum, src, volume); - if (!m_config.m_is_audio_initialized) + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) { return CELL_AUDIO_ERROR_NOT_INIT; } - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT || !src || src.addr() % 4) { return CELL_AUDIO_ERROR_PARAM; } - if (portNum >= m_config.AUDIO_PORT_COUNT || !src || src.addr() % 4) - { - return CELL_AUDIO_ERROR_PARAM; - } - - const AudioPortConfig& port = m_config.m_ports[portNum]; + const AudioPortConfig& port = g_audio.ports[portNum]; const auto dst = vm::ptr::make(port.addr + (port.tag % port.block) * port.channel * 256 * sizeof(float)); @@ -1004,7 +894,7 @@ s32 cellAudioAdd6chData(u32 portNum, vm::ptr src, float volume) { cellAudio->Error("cellAudioAdd6chData(portNum=%d): invalid port.channel value (%d)", portNum, port.channel); } - + return CELL_OK; } @@ -1036,6 +926,10 @@ void cellAudio_init(Module *pxThis) { cellAudio = pxThis; + g_audio.state.write_relaxed(AUDIO_STATE_NOT_INITIALIZED); + g_audio.buffer = 0; + g_audio.indexes = 0; + REG_FUNC(cellAudio, cellAudioInit); REG_FUNC(cellAudio, cellAudioPortClose); REG_FUNC(cellAudio, cellAudioPortStop); @@ -1060,3 +954,8 @@ void cellAudio_init(Module *pxThis) REG_FUNC(cellAudio, cellAudioSetPersonalDevice); REG_FUNC(cellAudio, cellAudioUnsetPersonalDevice); } + +void cellAudio_load() +{ + // never called :( +} diff --git a/rpcs3/Emu/Audio/cellAudio.h b/rpcs3/Emu/SysCalls/Modules/cellAudio.h similarity index 81% rename from rpcs3/Emu/Audio/cellAudio.h rename to rpcs3/Emu/SysCalls/Modules/cellAudio.h index b6cabcea59..83fd4fc097 100644 --- a/rpcs3/Emu/Audio/cellAudio.h +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.h @@ -72,10 +72,32 @@ struct CellAudioPortConfig be_t portAddr; }; +enum : u32 +{ + BUFFER_NUM = 32, + BUFFER_SIZE = 256, + AUDIO_PORT_COUNT = 8, +}; + +enum AudioState : u32 +{ + AUDIO_STATE_NOT_INITIALIZED, + AUDIO_STATE_INITIALIZED, + AUDIO_STATE_FINALIZED, +}; + +enum AudioPortState : u32 +{ + AUDIO_PORT_STATE_NOT_OPENED, + AUDIO_PORT_STATE_OPENED, + AUDIO_PORT_STATE_STARTED, +}; + struct AudioPortConfig { - bool m_is_audio_port_opened; - bool m_is_audio_port_started; + std::mutex mutex; + atomic_le_t state; + u8 channel; u8 block; float level; @@ -89,34 +111,20 @@ struct AudioPortConfig struct AudioConfig //custom structure { - enum - { - AUDIO_PORT_COUNT = 8, - }; - AudioPortConfig m_ports[AUDIO_PORT_COUNT]; - u32 m_buffer; // 1 MB memory for audio ports - u32 m_indexes; // current block indexes and other info - bool m_is_audio_initialized; - bool m_is_audio_finalized; - u32 m_port_in_use; + std::mutex mutex; + atomic_le_t state; + thread_t audio_thread; + + AudioPortConfig ports[AUDIO_PORT_COUNT]; + u32 buffer; // 1 MB memory for audio ports + u32 indexes; // current block indexes and other info u64 counter; u64 start_time; - std::vector m_keys; + std::vector keys; - AudioConfig() - : m_is_audio_initialized(false) - , m_is_audio_finalized(false) - , m_port_in_use(0) - , counter(0) + AudioConfig() : audio_thread("Audio Thread") { - memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT); - } - - void Clear() - { - memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT); - m_port_in_use = 0; } }; -extern AudioConfig m_config; +extern AudioConfig g_audio; diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index ff4cc079df..7670b22b4a 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -306,7 +306,7 @@ u32 dmuxOpen(Demuxer* dmux_ptr) dmux.id = dmux_id; dmux.dmuxCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); - dmux.dmuxCb->SetName("Demuxer[" + std::to_string(dmux_id) + "] Callback"); + dmux.dmuxCb->SetName(fmt::format("Demuxer[%d] Callback", dmux_id)); dmux.dmuxCb->SetEntry(0); dmux.dmuxCb->SetPrio(1001); dmux.dmuxCb->SetStackSize(0x10000); @@ -314,10 +314,9 @@ u32 dmuxOpen(Demuxer* dmux_ptr) dmux.dmuxCb->InitRegs(); dmux.dmuxCb->DoRun(); - thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [dmux_ptr, sptr]() + thread_t t(fmt::format("Demuxer[%d] Thread", dmux_id), [dmux_ptr, sptr]() { Demuxer& dmux = *dmux_ptr; - cellDmux->Notice("Demuxer thread started (mem=0x%x, size=0x%x, cb_addr=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc.addr(), dmux.cbArg); DemuxerTask task; DemuxerStream stream = {}; @@ -761,11 +760,8 @@ u32 dmuxOpen(Demuxer* dmux_ptr) dmux.is_finished = true; if (Emu.IsStopped()) cellDmux->Warning("Demuxer thread aborted"); - if (dmux.is_closed) cellDmux->Notice("Demuxer thread ended"); }); - t.detach(); - return dmux_id; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp b/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp index a652d134f9..64107c9461 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp @@ -123,7 +123,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::ptr msgString, vm::ptr msgString, vm::ptrSetName("Video Decoder[" + std::to_string(vdec_id) + "] Callback"); + vdec.vdecCb->SetName(fmt::format("VideoDecoder[%d] Callback", vdec_id)); vdec.vdecCb->SetEntry(0); vdec.vdecCb->SetPrio(1001); vdec.vdecCb->SetStackSize(0x10000); @@ -222,11 +222,9 @@ u32 vdecOpen(VideoDecoder* vdec_ptr) vdec.vdecCb->InitRegs(); vdec.vdecCb->DoRun(); - thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [vdec_ptr, sptr]() + thread_t t(fmt::format("VideoDecoder[%d] Thread", vdec_id), [vdec_ptr, sptr]() { VideoDecoder& vdec = *vdec_ptr; - cellVdec->Notice("Video Decoder thread started"); - VdecTask& task = vdec.task; while (true) @@ -431,7 +429,15 @@ u32 vdecOpen(VideoDecoder* vdec_ptr) { if (vdec.last_pts == -1) { - vdec.last_pts = 0x8000; //av_frame_get_best_effort_timestamp(frame.data); + u64 ts = av_frame_get_best_effort_timestamp(frame.data); + if (ts != AV_NOPTS_VALUE) + { + vdec.last_pts = ts; + } + else + { + vdec.last_pts = 0; + } } else switch (vdec.frc_set) { @@ -539,18 +545,15 @@ u32 vdecOpen(VideoDecoder* vdec_ptr) default: { - VDEC_ERROR("Video Decoder thread error: unknown task(%d)", task.type); + VDEC_ERROR("VideoDecoder thread error: unknown task(%d)", task.type); } } } vdec.is_finished = true; - if (Emu.IsStopped()) cellVdec->Warning("Video Decoder thread aborted"); - if (vdec.is_closed) cellVdec->Notice("Video Decoder thread ended"); + if (Emu.IsStopped()) cellVdec->Warning("VideoDecoder thread aborted"); }); - t.detach(); - return vdec_id; } diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp index a6859cf19b..9591474ec7 100644 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp @@ -5,7 +5,7 @@ #include "Emu/SysCalls/CB_FUNC.h" #include "Emu/CPU/CPUThreadManager.h" -#include "Emu/Audio/cellAudio.h" +#include "cellAudio.h" #include "libmixer.h" Module *libmixer = nullptr; @@ -298,9 +298,9 @@ int cellSurMixerCreate(vm::ptr config) surMixer = *config; - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; + AudioPortConfig& port = g_audio.ports[SUR_PORT]; - if (port.m_is_audio_port_opened) + if (!port.state.compare_and_swap_test(AUDIO_PORT_STATE_NOT_OPENED, AUDIO_PORT_STATE_OPENED)) { return CELL_LIBMIXER_ERROR_FULL; } @@ -309,22 +309,19 @@ int cellSurMixerCreate(vm::ptr config) port.block = 16; port.attr = 0; port.level = 1.0f; + port.tag = 0; libmixer->Warning("*** audio port opened(default)"); - port.m_is_audio_port_opened = true; - port.tag = 0; - m_config.m_port_in_use++; - - libmixer->Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", - (u32)surMixer.chStrips1, (u32)surMixer.chStrips2, (u32)surMixer.chStrips6, (u32)surMixer.chStrips8); - mixcount = 0; surMixerCb.set(0); - thread t("Surmixer Thread", []() + libmixer->Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", + (u32)surMixer.chStrips1, (u32)surMixer.chStrips2, (u32)surMixer.chStrips6, (u32)surMixer.chStrips8); + + thread_t t("Surmixer Thread", []() { - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; + AudioPortConfig& port = g_audio.ports[SUR_PORT]; PPUThread& cb_thread = *(PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); cb_thread.SetName("Surmixer Callback Thread"); @@ -335,7 +332,7 @@ int cellSurMixerCreate(vm::ptr config) cb_thread.InitRegs(); cb_thread.DoRun(); - while (port.m_is_audio_port_opened) + while (port.state.read_relaxed() != AUDIO_PORT_STATE_NOT_OPENED) { if (Emu.IsStopped()) { @@ -349,7 +346,7 @@ int cellSurMixerCreate(vm::ptr config) continue; } - if (port.m_is_audio_port_started) + if (port.state.read_relaxed() == AUDIO_PORT_STATE_STARTED) { //u64 stamp0 = get_system_time(); @@ -440,7 +437,7 @@ int cellSurMixerCreate(vm::ptr config) //u64 stamp2 = get_system_time(); - auto buf = vm::get_ptr>(m_config.m_buffer + (128 * 1024 * SUR_PORT) + (mixcount % port.block) * port.channel * 256 * sizeof(float)); + auto buf = vm::get_ptr>(g_audio.buffer + (128 * 1024 * SUR_PORT) + (mixcount % port.block) * port.channel * 256 * sizeof(float)); for (u32 i = 0; i < (sizeof(mixdata) / sizeof(float)); i++) { @@ -464,7 +461,6 @@ int cellSurMixerCreate(vm::ptr config) Emu.GetCPU().RemoveThread(cb_thread.GetId()); surMixerCb.set(0); }); - t.detach(); return CELL_OK; } @@ -515,13 +511,8 @@ int cellSurMixerStart() { libmixer->Warning("cellSurMixerStart()"); - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; + g_audio.ports[SUR_PORT].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED); - if (port.m_is_audio_port_opened) - { - port.m_is_audio_port_started = true; - } - return CELL_OK; } @@ -535,14 +526,7 @@ int cellSurMixerFinalize() { libmixer->Warning("cellSurMixerFinalize()"); - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; - - if (port.m_is_audio_port_opened) - { - port.m_is_audio_port_started = false; - port.m_is_audio_port_opened = false; - m_config.m_port_in_use--; - } + g_audio.ports[SUR_PORT].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_NOT_OPENED); return CELL_OK; } @@ -581,12 +565,7 @@ int cellSurMixerPause(u32 type) { libmixer->Warning("cellSurMixerPause(type=%d)", type); - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; - - if (port.m_is_audio_port_opened) - { - port.m_is_audio_port_started = false; - } + g_audio.ports[SUR_PORT].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED); return CELL_OK; } @@ -603,7 +582,7 @@ int cellSurMixerGetTimestamp(u64 tag, vm::ptr stamp) { libmixer->Log("cellSurMixerGetTimestamp(tag=0x%llx, stamp_addr=0x%x)", tag, stamp.addr()); - *stamp = m_config.start_time + (tag) * 256000000 / 48000; // ??? + *stamp = g_audio.start_time + (tag) * 256000000 / 48000; // ??? return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/cellFs.cpp b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp index 3fb8bf1db7..4f83878a83 100644 --- a/rpcs3/Emu/SysCalls/lv2/cellFs.cpp +++ b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp @@ -966,11 +966,7 @@ int cellFsAioRead(vm::ptr aio, vm::ptr id, vm::ptr + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 2f0baf5d6f..1ef837c8fd 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1279,5 +1279,8 @@ Emu\Audio\XAudio2 + + Emu\SysCalls\Modules + \ No newline at end of file