diff --git a/Utilities/SQueue.h b/Utilities/SQueue.h index d98f13d793..7b52644771 100644 --- a/Utilities/SQueue.h +++ b/Utilities/SQueue.h @@ -15,6 +15,11 @@ public: { } + const u32 GetSize() const + { + return SQSize; + } + bool Push(const T& data) { while (true) diff --git a/rpcs3/Emu/Audio/AudioDumper.cpp b/rpcs3/Emu/Audio/AudioDumper.cpp index dbd282e7ae..118ffd6623 100644 --- a/rpcs3/Emu/Audio/AudioDumper.cpp +++ b/rpcs3/Emu/Audio/AudioDumper.cpp @@ -23,7 +23,7 @@ void AudioDumper::WriteHeader() size_t AudioDumper::WriteData(const void* buffer, size_t size) { - for (u32 i = 0; i < size / 8; i++) + /*for (u32 i = 0; i < size / 8; i++) { if (((u64*)buffer)[i]) goto process; } @@ -32,7 +32,7 @@ size_t AudioDumper::WriteData(const void* buffer, size_t size) if (((u8*)buffer)[i + (size & ~7)]) goto process; } return size; // ignore empty data -process: +process:*/ size_t ret = m_output.Write(buffer, size); m_header.Size += ret; m_header.RIFF.Size += ret; diff --git a/rpcs3/Emu/Audio/cellAudio.h b/rpcs3/Emu/Audio/cellAudio.h index dc371c9c67..c0fe570980 100644 --- a/rpcs3/Emu/Audio/cellAudio.h +++ b/rpcs3/Emu/Audio/cellAudio.h @@ -1,5 +1,7 @@ #pragma once +extern u64 get_system_time(); + // Error codes enum { @@ -20,16 +22,6 @@ enum CELL_AUDIO_ERROR_AUDIOSYSTEM_NOT_FOUND = 0x8031070e, CELL_AUDIO_ERROR_TAG_NOT_FOUND = 0x8031070f, - //libmixer Error Codes - CELL_LIBMIXER_ERROR_NOT_INITIALIZED = 0x80310002, - CELL_LIBMIXER_ERROR_INVALID_PARAMATER = 0x80310003, - CELL_LIBMIXER_ERROR_NO_MEMORY = 0x80310005, - CELL_LIBMIXER_ERROR_ALREADY_EXIST = 0x80310006, - CELL_LIBMIXER_ERROR_FULL = 0x80310007, - CELL_LIBMIXER_ERROR_NOT_EXIST = 0x80310008, - CELL_LIBMIXER_ERROR_TYPE_MISMATCH = 0x80310009, - CELL_LIBMIXER_ERROR_NOT_FOUND = 0x8031000a, - //libsnd3 Error Codes CELL_SND3_ERROR_PARAM = 0x80310301, CELL_SND3_ERROR_CREATE_MUTEX = 0x80310302, @@ -108,7 +100,6 @@ struct CellAudioPortConfig struct AudioPortConfig { - SMutexGeneral m_mutex; bool m_is_audio_port_opened; bool m_is_audio_port_started; u8 channel; @@ -121,7 +112,6 @@ struct AudioPortConfig struct AudioConfig //custom structure { - std::mutex m_mutex; enum { AUDIO_PORT_COUNT = 8, @@ -150,7 +140,9 @@ struct AudioConfig //custom structure memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT); m_port_in_use = 0; } -} m_config; +}; + +extern AudioConfig m_config; //libsnd3 datatypes struct CellSnd3DataCtx diff --git a/rpcs3/Emu/SysCalls/Modules.h b/rpcs3/Emu/SysCalls/Modules.h index 165f59a49d..ffaefb64d4 100644 --- a/rpcs3/Emu/SysCalls/Modules.h +++ b/rpcs3/Emu/SysCalls/Modules.h @@ -34,8 +34,11 @@ struct SFuncOp struct SFunc { func_caller* func; + void* ptr; char* name; Array ops; + u64 group; + u32 found; }; extern ArrayF g_static_funcs_list; @@ -110,7 +113,7 @@ public: template __forceinline void AddFunc(u32 id, T func); - template __forceinline void AddFuncSub(const u64 ops[], char* name, T func); + template __forceinline void AddFuncSub(const char group[8], const u64 ops[], char* name, T func); }; template @@ -120,13 +123,16 @@ __forceinline void Module::AddFunc(u32 id, T func) } template -__forceinline void Module::AddFuncSub(const u64 ops[], char* name, T func) +__forceinline void Module::AddFuncSub(const char group[8], const u64 ops[], char* name, T func) { if (!ops[0]) return; SFunc* sf = new SFunc; + sf->ptr = func; sf->func = bind_func(func); sf->name = name; + sf->group = *(u64*)group; + sf->found = 0; // TODO: check for self-inclusions, use CRC diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index fec5d753be..61f4f27d56 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -63,8 +63,6 @@ next: adec.reader.addr = adec.task.au.addr; adec.reader.size = adec.task.au.size; //ConLog.Write("Audio AU: size = 0x%x, pts = 0x%llx", adec.task.au.size, adec.task.au.pts); - - //if (adec.last_pts > adec.task.au.pts) adec.last_pts = adec.task.au.pts; } break; default: @@ -266,8 +264,11 @@ u32 adecOpen(AudioDecoder* data) adec.reader.size = task.au.size; //ConLog.Write("Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts); - //if (adec.last_pts > task.au.pts || adec.just_started) adec.last_pts = task.au.pts; - if (adec.just_started) adec.last_pts = task.au.pts; + if (adec.just_started) + { + adec.first_pts = task.au.pts; + adec.last_pts = task.au.pts /*- 3816*8*/; // hack + } struct AVPacketHolder : AVPacket { @@ -433,8 +434,19 @@ u32 adecOpen(AudioDecoder* data) if (got_frame) { - frame.pts = adec.last_pts; - adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / 48000; // ??? + u64 ts = av_frame_get_best_effort_timestamp(frame.data); + if (ts != AV_NOPTS_VALUE) + { + frame.pts = ts/* - adec.first_pts*/; + adec.last_pts = frame.pts; + } + else + { + adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / 48000; + frame.pts = adec.last_pts; + } + //frame.pts = adec.last_pts; + //adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / 48000; // ??? frame.auAddr = task.au.addr; frame.auSize = task.au.size; frame.userdata = task.au.userdata; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.h b/rpcs3/Emu/SysCalls/Modules/cellAdec.h index 66364a6084..3e29c92b1a 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.h +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.h @@ -1114,7 +1114,7 @@ public: u32 memBias; AdecTask task; - u64 last_pts; + u64 last_pts, first_pts; CPUThread* adecCb; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index 59fc40a276..9813fe763f 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SC_FUNC.h" +#include "Utilities/SQueue.h" #include "Emu/Audio/cellAudio.h" #include "Emu/Audio/AudioManager.h" #include "Emu/Audio/AudioDumper.h" @@ -9,7 +10,9 @@ void cellAudio_init(); void cellAudio_unload(); Module cellAudio(0x0011, cellAudio_init, nullptr, cellAudio_unload); -extern u64 get_system_time(); +static SMutexGeneral audioMutex; + +AudioConfig m_config; // libaudio Functions @@ -23,6 +26,7 @@ int cellAudioInit() } m_config.m_is_audio_initialized = true; + m_config.start_time = 0; m_config.counter = 0; // alloc memory @@ -43,31 +47,57 @@ int cellAudioInit() ConLog.Write("Audio started"); - m_config.start_time = get_system_time(); - if (Ini.AudioDumpToFile.GetValue()) m_dump.WriteHeader(); float buffer[2*256]; // buffer for 2 channels be_t buffer2[8*256]; // buffer for 8 channels (max count) //u16 oal_buffer[2*256]; // buffer for OpenAL + memset(buffer, 0, sizeof(buffer)); + memset(buffer2, 0, sizeof(buffer2)); uint oal_buffer_offset = 0; uint oal_buffer_size = 2 * 256; - std::unique_ptr oal_buffer(new u16[oal_buffer_size]); - - memset(buffer, 0, sizeof(buffer)); - memset(buffer2, 0, sizeof(buffer2)); - memset(oal_buffer.get(), 0, oal_buffer_size * sizeof(u16)); + std::unique_ptr oal_buffer[32]; + SQueue queue; + for (u32 i = 0; i < queue.GetSize(); i++) + { + oal_buffer[i] = std::unique_ptr(new u16[oal_buffer_size]); + memset(oal_buffer[i].get(), 0, oal_buffer_size * sizeof(u16)); + } + queue.Clear(); + //std::unique_ptr oal_buf(new u16[oal_buffer_size]); + //memset(oal_buffer.get(), 0, oal_buffer_size * sizeof(u16)); Array keys; if(m_audio_out) { m_audio_out->Init(); - m_audio_out->Open(oal_buffer.get(), oal_buffer_size*sizeof(u16)); + m_audio_out->Open(oal_buffer[0].get(), oal_buffer_size * sizeof(u16)); } + m_config.start_time = get_system_time(); + + thread iat("Internal Audio Thread", [oal_buffer_size, &queue]() + { + while (true) + { + u16* oal_buffer = nullptr; + queue.Pop(oal_buffer); + + if (oal_buffer) + { + m_audio_out->AddData(oal_buffer, oal_buffer_size * sizeof(u16)); + } + else + { + break; + } + } + }); + iat.detach(); + while (m_config.m_is_audio_initialized) { if (Emu.IsStopped()) @@ -76,10 +106,12 @@ int cellAudioInit() goto abort; } + const u64 stamp0 = get_system_time(); + // TODO: send beforemix event (in ~2,6 ms before mixing) - // Sleep(5); // precise time of sleeping: 5,(3) ms (or 256/48000 sec) - if (m_config.counter * 256000000 / 48000 >= get_system_time() - m_config.start_time) + // precise time of sleeping: 5,(3) ms (or 256/48000 sec) + if (m_config.counter * 256000000 / 48000 >= stamp0 - m_config.start_time) { Sleep(1); continue; @@ -87,6 +119,8 @@ int cellAudioInit() m_config.counter++; + const u32 oal_pos = m_config.counter % queue.GetSize(); + if (Emu.IsPaused()) { continue; @@ -112,13 +146,13 @@ int cellAudioInit() memset(Memory + buf_addr, 0, block_size * sizeof(float)); { - SMutexGeneralLocker lock(port.m_mutex); + SMutexGeneralLocker lock(audioMutex); port.counter = m_config.counter; port.tag++; // absolute index of block that will be read index = (position + 1) % port.block; // write new value } - u32 k = port.channel / 2; + const u32 k = port.channel / 2; if (first_mix) { @@ -129,10 +163,10 @@ int cellAudioInit() buffer[i+1] = buffer2[i*k+1]; // convert the data from float to u16 - assert(buffer[i] >= -4.0f && buffer[i] <= 4.0f); - assert(buffer[i+1] >= -4.0f && buffer[i+1] <= 4.0f); - oal_buffer[oal_buffer_offset + i] = (u16)(buffer[i] * ((1 << 13) - 1)); - oal_buffer[oal_buffer_offset + i + 1] = (u16)(buffer[i+1] * ((1 << 13) - 1)); + //assert(buffer[i] >= -1.0f && buffer[i] <= 1.0f); + //assert(buffer[i+1] >= -1.0f && buffer[i+1] <= 1.0f); + oal_buffer[oal_pos][oal_buffer_offset + i] = (u16)(buffer[i] * ((1 << 14) - 1)); + oal_buffer[oal_pos][oal_buffer_offset + i + 1] = (u16)(buffer[i+1] * ((1 << 14) - 1)); } first_mix = false; @@ -145,17 +179,19 @@ int cellAudioInit() buffer[i+1] = (buffer[i+1] + buffer2[i*k+1]) * 0.5; // convert the data from float to u16 - assert(buffer[i] >= -4.0f && buffer[i] <= 4.0f); - assert(buffer[i+1] >= -4.0f && buffer[i+1] <= 4.0f); - oal_buffer[oal_buffer_offset + i] = (u16)(buffer[i] * ((1 << 13) - 1)); - oal_buffer[oal_buffer_offset + i + 1] = (u16)(buffer[i+1] * ((1 << 13) - 1)); + //assert(buffer[i] >= -1.0f && buffer[i] <= 1.0f); + //assert(buffer[i+1] >= -1.0f && buffer[i+1] <= 1.0f); + oal_buffer[oal_pos][oal_buffer_offset + i] = (u16)(buffer[i] * ((1 << 14) - 1)); + oal_buffer[oal_pos][oal_buffer_offset + i + 1] = (u16)(buffer[i+1] * ((1 << 14) - 1)); } } } + const u64 stamp1 = get_system_time(); + // send aftermix event (normal audio event) { - std::lock_guard lock(m_config.m_mutex); + SMutexGeneralLocker lock(audioMutex); keys.SetCount(m_config.m_keys.GetCount()); memcpy(keys.GetPtr(), m_config.m_keys.GetPtr(), sizeof(u64) * keys.GetCount()); } @@ -165,18 +201,22 @@ int cellAudioInit() Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0); } + const u64 stamp2 = get_system_time(); + oal_buffer_offset += sizeof(buffer) / sizeof(float); if(oal_buffer_offset >= oal_buffer_size) { if(m_audio_out) { - m_audio_out->AddData(oal_buffer.get(), oal_buffer_offset * sizeof(u16)); + queue.Push(&oal_buffer[oal_pos][0]); } oal_buffer_offset = 0; } + const u64 stamp3 = get_system_time(); + if(Ini.AudioDumpToFile.GetValue()) { if (m_dump.WriteData(&buffer, sizeof(buffer)) != sizeof(buffer)) // write file data @@ -185,16 +225,37 @@ int cellAudioInit() goto abort; } } + + const u64 stamp4 = get_system_time(); + + //ConLog.Write("Audio perf: start=%d (access=%d, event=%d, AddData=%d, dump=%d)", + //stamp0 - m_config.start_time, stamp1-stamp0, stamp2-stamp1, stamp3-stamp2, stamp4-stamp3); } ConLog.Write("Audio finished"); abort: + queue.Push(nullptr); + while (queue.GetCount()) + { + Sleep(1); + } if(Ini.AudioDumpToFile.GetValue()) m_dump.Finalize(); m_config.m_is_audio_finalized = true; + m_config.m_is_audio_initialized = false; }); t.detach(); + while (!m_config.start_time) // waiting for initialization + { + if (Emu.IsStopped()) + { + ConLog.Warning("cellAudioInit() aborted"); + return CELL_OK; + } + Sleep(1); + } + return CELL_OK; } @@ -395,7 +456,7 @@ int cellAudioGetPortTimestamp(u32 portNum, u64 tag, mem64_t stamp) AudioPortConfig& port = m_config.m_ports[portNum]; - SMutexGeneralLocker lock(port.m_mutex); + SMutexGeneralLocker lock(audioMutex); stamp = m_config.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000; @@ -429,7 +490,7 @@ int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, mem64_t tag) return CELL_AUDIO_ERROR_PARAM; } - SMutexGeneralLocker lock(port.m_mutex); + SMutexGeneralLocker lock(audioMutex); u64 tag_base = port.tag; if (tag_base % port.block > blockNo) @@ -457,7 +518,7 @@ int cellAudioCreateNotifyEventQueue(mem32_t id, mem64_t key) { cellAudio.Warning("cellAudioCreateNotifyEventQueue(id_addr=0x%x, key_addr=0x%x)", id.GetAddr(), key.GetAddr()); - std::lock_guard lock(m_config.m_mutex); + SMutexGeneralLocker lock(audioMutex); u64 event_key = 0; while (Emu.GetEventManager().CheckKey((event_key << 48) | 0x80004d494f323221)) @@ -475,7 +536,6 @@ int cellAudioCreateNotifyEventQueue(mem32_t id, mem64_t key) return CELL_AUDIO_ERROR_EVENT_QUEUE; } - m_config.m_keys.AddCpy(event_key); id = cellAudio.GetNewId(eq); key = event_key; @@ -492,8 +552,15 @@ int cellAudioSetNotifyEventQueue(u64 key) { cellAudio.Warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key); - std::lock_guard lock(m_config.m_mutex); + SMutexGeneralLocker lock(audioMutex); + for (u32 i = 0; i < m_config.m_keys.GetCount(); i++) // check for duplicates + { + if (m_config.m_keys[i] == key) + { + return CELL_AUDIO_ERROR_PARAM; + } + } m_config.m_keys.AddCpy(key); /*EventQueue* eq; @@ -517,7 +584,7 @@ int cellAudioRemoveNotifyEventQueue(u64 key) { cellAudio.Warning("cellAudioRemoveNotifyEventQueue(key=0x%llx)", key); - std::lock_guard lock(m_config.m_mutex); + SMutexGeneralLocker lock(audioMutex); bool found = false; for (u32 i = 0; i < m_config.m_keys.GetCount(); i++) diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index 1e49e653d5..32581f3567 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -67,9 +67,6 @@ next: vdec.reader.addr = vdec.task.addr; vdec.reader.size = vdec.task.size; //ConLog.Write("Video AU: size = 0x%x, pts = 0x%llx, dts = 0x%llx", vdec.task.size, vdec.task.pts, vdec.task.dts); - - //if (vdec.last_pts > vdec.task.pts) vdec.last_pts = vdec.task.pts; - //if (vdec.last_dts > vdec.task.dts) vdec.last_dts = vdec.task.dts; } break; default: @@ -208,12 +205,11 @@ u32 vdecOpen(VideoDecoder* data) vdec.reader.size = task.size; //ConLog.Write("Video AU: size = 0x%x, pts = 0x%llx, dts = 0x%llx", task.size, task.pts, task.dts); - //if (vdec.last_pts > task.pts || vdec.just_started) vdec.last_pts = task.pts; - //if (vdec.last_dts > task.dts || vdec.just_started) vdec.last_dts = task.dts; if (vdec.just_started) { + vdec.first_pts = task.pts; vdec.last_pts = task.pts; - vdec.last_dts = task.dts; + vdec.first_dts = task.dts; } struct AVPacketHolder : AVPacket @@ -357,8 +353,20 @@ u32 vdecOpen(VideoDecoder* data) if (got_picture) { - frame.dts = vdec.last_dts; vdec.last_dts += 3003; // + duration??? - frame.pts = vdec.last_pts; vdec.last_pts += 3003; + u64 ts = av_frame_get_best_effort_timestamp(frame.data); + if (ts != AV_NOPTS_VALUE) + { + frame.pts = ts/* - vdec.first_pts*/; // ??? + vdec.last_pts = frame.pts; + } + else + { + vdec.last_pts += vdec.ctx->time_base.num * 90000 / (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame); + frame.pts = vdec.last_pts; + } + //frame.pts = vdec.last_pts; + //vdec.last_pts += 3754; + frame.dts = (frame.pts - vdec.first_pts) + vdec.first_dts; frame.userdata = task.userData; //ConLog.Write("got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts); @@ -726,7 +734,27 @@ int cellVdecGetPicItem(u32 handle, mem32_t picItem_ptr) avc->transfer_characteristics = CELL_VDEC_AVC_TC_ITU_R_BT_709_5; avc->matrix_coefficients = CELL_VDEC_AVC_MXC_ITU_R_BT_709_5; // important avc->timing_info_present_flag = true; - avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001; // important (!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!) + if (vdec->ctx->time_base.num == 1001) + { + if (vdec->ctx->time_base.den == 48000 && vdec->ctx->ticks_per_frame == 2) + { + avc->frameRateCode = CELL_VDEC_AVC_FRC_24000DIV1001; + } + else if (vdec->ctx->time_base.den == 60000 && vdec->ctx->ticks_per_frame == 2) + { + avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001; + } + else + { + ConLog.Error("cellVdecGetPicItem: unsupported time_base.den (%d)", vdec->ctx->time_base.den); + Emu.Pause(); + } + } + else + { + ConLog.Error("cellVdecGetPicItem: unsupported time_base.num (%d)", vdec->ctx->time_base.num); + Emu.Pause(); + } avc->fixed_frame_rate_flag = true; avc->low_delay_hrd_flag = true; // ??? avc->entropy_coding_mode_flag = true; // ??? diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.h b/rpcs3/Emu/SysCalls/Modules/cellVdec.h index 96534cdbe2..65adee08e0 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.h +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.h @@ -719,7 +719,8 @@ public: u32 memBias; VdecTask task; // current task variable - u64 last_pts, last_dts; + u64 last_pts, first_pts, first_dts; + AVRational rfr, afr; CPUThread* vdecCb; diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp index cb2b3bb547..53ec449bfd 100644 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp @@ -1,15 +1,47 @@ #include "stdafx.h" #include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SC_FUNC.h" +#include "Emu/Audio/cellAudio.h" #include "libmixer.h" void libmixer_init(); Module libmixer("libmixer", libmixer_init); -int cellAANAddData(u32 handle, u32 port, u32 offset, u32 addr, u32 samples) +CellSurMixerConfig surMixer; + +#define SUR_PORT (7) +u32 surMixerCb = 0; +u32 surMixerCbArg = 0; +u64 mixcount = 0, stamp1 = 0, stamp2 = 0; + +int cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, u32 addr, u32 samples) { - libmixer.Error("cellAANAddData(handle=0x%x, port=0x%x, offset=0x%x, addr=0x%x, samples=0x%x)", - handle, port, offset, addr, samples); + stamp1 = get_system_time(); + + if (aan_handle == 0x11111111 && aan_port == (2 << 16)) + { + libmixer.Log("cellAANAddData(handle=0x%x, port=0x%x, offset=0x%x, addr=0x%x, samples=0x%x)", + aan_handle, aan_port, offset, addr, samples); + } + else + { + libmixer.Error("cellAANAddData(handle=0x%x, port=0x%x, offset=0x%x, addr=0x%x, samples=0x%x)", + aan_handle, aan_port, offset, addr, samples); + Emu.Pause(); + return CELL_OK; + } + + AudioPortConfig& port = m_config.m_ports[SUR_PORT]; + + u32 to = m_config.m_buffer + (128 * 1024 * SUR_PORT) + ((mixcount + 12) % 16) * 2 * 256 * sizeof(float) + offset; + + if (!Memory.Copy(to, addr, 2 * samples * sizeof(float))) + { + return CELL_LIBMIXER_ERROR_NO_MEMORY; + } + + stamp2 = get_system_time(); + return CELL_OK; } @@ -71,49 +103,127 @@ s32 cellSSPlayerGetState() //CellAANHandle handle int cellSurMixerCreate(const mem_ptr_t config) { - libmixer.Error("cellSurMixerCreate(config_addr=0x%x)", config.GetAddr()); + libmixer.Warning("cellSurMixerCreate(config_addr=0x%x)", config.GetAddr()); + surMixer = *config; + libmixer.Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", + (u32)surMixer.chStrips1, (u32)surMixer.chStrips2, (u32)surMixer.chStrips6, (u32)surMixer.chStrips8); return CELL_OK; } int cellSurMixerGetAANHandle(mem32_t handle) { - libmixer.Error("cellSurMixerGetAANHandle(handle_addr=0x%x)", handle.GetAddr()); + libmixer.Warning("cellSurMixerGetAANHandle(handle_addr=0x%x) -> 0x11111111", handle.GetAddr()); + handle = 0x11111111; return CELL_OK; } int cellSurMixerChStripGetAANPortNo(mem32_t port, u32 type, u32 index) { - libmixer.Error("cellSurMixerChStripGetAANPortNo(port_addr=0x%x, type=0x%x, index=0x%x)", port.GetAddr(), type, index); + libmixer.Warning("cellSurMixerChStripGetAANPortNo(port_addr=0x%x, type=0x%x, index=0x%x) -> 0", port.GetAddr(), type, index); + port = (type << 16) | index; return CELL_OK; } int cellSurMixerSetNotifyCallback(u32 func, u32 arg) { - libmixer.Error("cellSurMixerSetNotifyCallback(func_addr=0x%x, arg=0x%x)", func, arg); + libmixer.Warning("cellSurMixerSetNotifyCallback(func_addr=0x%x, arg=0x%x)", func, arg); + surMixerCb = func; + surMixerCbArg = arg; return CELL_OK; } int cellSurMixerRemoveNotifyCallback(u32 func) { - libmixer.Error("cellSurMixerSetNotifyCallback(func_addr=0x%x)", func); + libmixer.Warning("cellSurMixerSetNotifyCallback(func_addr=0x%x)", func); + surMixerCb = 0; + surMixerCbArg = 0; return CELL_OK; } int cellSurMixerStart() { - libmixer.Error("cellSurMixerStart()"); + libmixer.Warning("cellSurMixerStart()"); + + AudioPortConfig& port = m_config.m_ports[SUR_PORT]; + + if (port.m_is_audio_port_opened) + { + return CELL_LIBMIXER_ERROR_FULL; + } + + port.channel = 2; + port.block = 16; + port.attr = 0; + port.level = 1.0f; + + libmixer.Warning("*** audio port opened(default, port 7)"); + + port.m_is_audio_port_opened = true; + port.tag = 0; + m_config.m_port_in_use++; + port.m_is_audio_port_started = true; + + thread t("Libmixer Thread", []() + { + AudioPortConfig& port = m_config.m_ports[SUR_PORT]; + + CPUThread* mixerCb = &Emu.GetCPU().AddThread(CPU_THREAD_PPU); + + mixerCb->SetName("Libmixer Callback"); + + mixcount = 0; + + while (port.m_is_audio_port_started) + { + if (Emu.IsStopped()) + { + ConLog.Warning("Libmixer aborted"); + return; + } + + if (mixcount > port.tag) + { + Sleep(1); + continue; + } + + u64 stamp0 = get_system_time(); + stamp1 = 0; + stamp2 = 0; + + mixerCb->ExecAsCallback(surMixerCb, true, surMixerCbArg, mixcount, 256); + + u64 stamp3 = get_system_time(); + + //ConLog.Write("Libmixer perf: start=%d (cb_before=%d, cb=%d, cb_after=%d)", + //stamp0 - m_config.start_time, stamp1-stamp0, stamp2-stamp1, stamp3-stamp2); + + mixcount++; + } + + Emu.GetCPU().RemoveThread(mixerCb->GetId()); + }); + t.detach(); + return CELL_OK; } int cellSurMixerSetParameter(u32 param, float value) { - libmixer.Error("cellSurMixerSetParameter(param=0x%x, value=%f)", param, value); + libmixer.Warning("cellSurMixerSetParameter(param=0x%x, value=%f)", param, value); return CELL_OK; } int cellSurMixerFinalize() { - libmixer.Error("cellSurMixerFinalize()"); + libmixer.Warning("cellSurMixerFinalize()"); + + AudioPortConfig& port = m_config.m_ports[SUR_PORT]; + + port.m_is_audio_port_started = false; + port.m_is_audio_port_opened = false; + m_config.m_port_in_use--; + return CELL_OK; } @@ -198,7 +308,7 @@ void libmixer_init() 0xffffffff4e800020, 0 }; - libmixer.AddFuncSub(cellAANAddData_table, "cellAANAddData", cellAANAddData); + libmixer.AddFuncSub("mixerAAN", cellAANAddData_table, "cellAANAddData", cellAANAddData); u64 cellAANConnect_table[39] = { 0xfffffffff821ff71, @@ -241,9 +351,9 @@ void libmixer_init() 0xffffffff4e800020, 0, // [38] }; - libmixer.AddFuncSub(cellAANConnect_table, "cellAANConnect", cellAANConnect); + libmixer.AddFuncSub("mixerAAN", cellAANConnect_table, "cellAANConnect", cellAANConnect); cellAANConnect_table[24] = 0xffffffff812b001c; - libmixer.AddFuncSub(cellAANConnect_table, "cellAANDisconnect", cellAANDisconnect); + libmixer.AddFuncSub("mixerAAN", cellAANConnect_table, "cellAANDisconnect", cellAANDisconnect); static const u64 cellAANAddData_table1[] = { // TODO @@ -272,7 +382,7 @@ void libmixer_init() 0xffffffff4e800020, 0 }; - libmixer.AddFuncSub(cellAANAddData_table1, "cellAANAddData(1)", cellAANAddData); + libmixer.AddFuncSub("mixerAAN", cellAANAddData_table1, "cellAANAddData(1)", cellAANAddData); static const u64 cellSurMixerCreate_table[] = { 0xffffffff2f830000, @@ -303,7 +413,7 @@ void libmixer_init() 0xffffffff382100b0, 0 }; - libmixer.AddFuncSub(cellSurMixerCreate_table, "cellSurMixerCreate", cellSurMixerCreate); + libmixer.AddFuncSub("surMixer", cellSurMixerCreate_table, "cellSurMixerCreate", cellSurMixerCreate); static const u64 cellSurMixerGetAANHandle_table[] = { // first instruction ignored @@ -322,7 +432,7 @@ void libmixer_init() 0xffffffff4e800020, 0 }; - libmixer.AddFuncSub(cellSurMixerGetAANHandle_table, "cellSurMixerGetAANHandle", cellSurMixerGetAANHandle); + libmixer.AddFuncSub("surMixer", cellSurMixerGetAANHandle_table, "cellSurMixerGetAANHandle", cellSurMixerGetAANHandle); static const u64 cellSurMixerChStripGetAANPortNo_table[] = { // first instruction ignored @@ -339,7 +449,7 @@ void libmixer_init() 0xf000000040000000, // b 0 }; - libmixer.AddFuncSub(cellSurMixerChStripGetAANPortNo_table, "cellSurMixerChStripGetAANPortNo", cellSurMixerChStripGetAANPortNo); + libmixer.AddFuncSub("surMixer", cellSurMixerChStripGetAANPortNo_table, "cellSurMixerChStripGetAANPortNo", cellSurMixerChStripGetAANPortNo); static const u64 cellSurMixerSetNotifyCallback_table[] = { // first instruction ignored @@ -369,7 +479,7 @@ void libmixer_init() 0xffffffff7d234b78, 0 }; - libmixer.AddFuncSub(cellSurMixerSetNotifyCallback_table, "cellSurMixerSetNotifyCallback", cellSurMixerSetNotifyCallback); + libmixer.AddFuncSub("surMixer", cellSurMixerSetNotifyCallback_table, "cellSurMixerSetNotifyCallback", cellSurMixerSetNotifyCallback); static const u64 cellSurMixerRemoveNotifyCallback_table[] = { // first instruction ignored @@ -389,7 +499,7 @@ void libmixer_init() 0xffffffff4e800020, 0 }; - libmixer.AddFuncSub(cellSurMixerRemoveNotifyCallback_table, "cellSurMixerRemoveNotifyCallback", cellSurMixerRemoveNotifyCallback); + libmixer.AddFuncSub("surMixer", cellSurMixerRemoveNotifyCallback_table, "cellSurMixerRemoveNotifyCallback", cellSurMixerRemoveNotifyCallback); static const u64 cellSurMixerStart_table[] = { 0xfffffffff821ff71, @@ -414,7 +524,7 @@ void libmixer_init() 0xffffffff4e800020, 0 }; - libmixer.AddFuncSub(cellSurMixerStart_table, "cellSurMixerStart", cellSurMixerStart); + libmixer.AddFuncSub("surMixer", cellSurMixerStart_table, "cellSurMixerStart", cellSurMixerStart); static const u64 cellSurMixerSetParameter_table[] = { 0xfffffffff821ff81, @@ -446,7 +556,7 @@ void libmixer_init() 0xffff0000409d0054, // ble 0 }; - libmixer.AddFuncSub(cellSurMixerSetParameter_table, "cellSurMixerSetParameter", cellSurMixerSetParameter); + libmixer.AddFuncSub("surMixer", cellSurMixerSetParameter_table, "cellSurMixerSetParameter", cellSurMixerSetParameter); static const u64 cellSurMixerFinalize_table[] = { 0xfffffffff821ff91, @@ -474,5 +584,5 @@ void libmixer_init() 0xffffffff4e800421, 0 }; - libmixer.AddFuncSub(cellSurMixerFinalize_table, "cellSurMixerFinalize", cellSurMixerFinalize); + libmixer.AddFuncSub("surMixer", cellSurMixerFinalize_table, "cellSurMixerFinalize", cellSurMixerFinalize); } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.h b/rpcs3/Emu/SysCalls/Modules/libmixer.h index 24c30c7b70..fe56a85ab6 100644 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.h +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.h @@ -1,5 +1,17 @@ #pragma once +enum +{ + //libmixer Error Codes + CELL_LIBMIXER_ERROR_NOT_INITIALIZED = 0x80310002, + CELL_LIBMIXER_ERROR_INVALID_PARAMATER = 0x80310003, + CELL_LIBMIXER_ERROR_NO_MEMORY = 0x80310005, + CELL_LIBMIXER_ERROR_ALREADY_EXIST = 0x80310006, + CELL_LIBMIXER_ERROR_FULL = 0x80310007, + CELL_LIBMIXER_ERROR_NOT_EXIST = 0x80310008, + CELL_LIBMIXER_ERROR_TYPE_MISMATCH = 0x80310009, + CELL_LIBMIXER_ERROR_NOT_FOUND = 0x8031000a, +}; //Callback Functions typedef int (*CellSurMixerNotifyCallbackFunction)(void *arg, u32 counter, u32 samples); //Currently unused. diff --git a/rpcs3/Emu/SysCalls/Static.cpp b/rpcs3/Emu/SysCalls/Static.cpp index 2628a77272..6a8369b701 100644 --- a/rpcs3/Emu/SysCalls/Static.cpp +++ b/rpcs3/Emu/SysCalls/Static.cpp @@ -9,8 +9,6 @@ void StaticAnalyse(void* ptr, u32 size) { u32* data = (u32*)ptr; size /= 4; - return; // disabled - // TODO: optimize search for (u32 i = 0; i < size; i++) { @@ -36,7 +34,8 @@ void StaticAnalyse(void* ptr, u32 size) } if (found) { - ConLog.Success("Function '%s' hooked", wxString(g_static_funcs_list[j].name).wx_str()); + //ConLog.Success("Function '%s' hooked", wxString(g_static_funcs_list[j].name).wx_str()); + g_static_funcs_list[j].found++; data[i] = re(0x39600000 | j); // li r11, j data[i+1] = se32(0x44000003); // sc 3 data[i+2] = se32(0x4e800020); // blr @@ -45,6 +44,91 @@ void StaticAnalyse(void* ptr, u32 size) } } } + + // check function groups + for (u32 i = 0; i < g_static_funcs_list.GetCount(); i++) + { + if (g_static_funcs_list[i].found) // start from some group + { + const u64 group = g_static_funcs_list[i].group; + + enum GroupSearchResult : u32 + { + GSR_SUCCESS = 0, // every function from this group has been found + GSR_MISSING = 1, // (error) not every function found + GSR_EXCESS = 2, // (error) some function found twice or more + }; + u32 res = GSR_SUCCESS; + + // analyse + for (u32 j = i; j < g_static_funcs_list.GetCount(); j++) if (g_static_funcs_list[j].group == group) + { + u32 count = g_static_funcs_list[j].found; + + if (count == 0) // not found + { + // check if this function has been found with different pattern + for (u32 k = i; k < g_static_funcs_list.GetCount(); k++) if (g_static_funcs_list[k].group == group) + { + if (k != j && g_static_funcs_list[k].ptr == g_static_funcs_list[j].ptr) + { + count += g_static_funcs_list[k].found; + } + } + if (count == 0) + { + res |= GSR_MISSING; + ConLog.Error("Function '%s' not found", wxString(g_static_funcs_list[j].name).wx_str()); + } + else if (count > 1) + { + res |= GSR_EXCESS; + } + } + else if (count == 1) // found + { + // ensure that this function has NOT been found with different pattern + for (u32 k = i; k < g_static_funcs_list.GetCount(); k++) if (g_static_funcs_list[k].group == group) + { + if (k != j && g_static_funcs_list[k].ptr == g_static_funcs_list[j].ptr) + { + if (g_static_funcs_list[k].found) + { + res |= GSR_EXCESS; + ConLog.Error("Function '%s' hooked twice", wxString(g_static_funcs_list[j].name).wx_str()); + } + } + } + } + else + { + res |= GSR_EXCESS; + ConLog.Error("Function '%s' hooked twice", wxString(g_static_funcs_list[j].name).wx_str()); + } + } + + // clear data + for (u32 j = i; j < g_static_funcs_list.GetCount(); j++) + { + if (g_static_funcs_list[j].group == group) g_static_funcs_list[j].found = 0; + } + + char name[9] = "????????"; + + *(u64*)name = group; + + if (res == GSR_SUCCESS) + { + ConLog.Success("Function group [%s] successfully hooked", wxString(name, 9).wx_str()); + } + else + { + ConLog.Error("Function group [%s] failed: %s%s", wxString(name, 9).wx_str(), + wxString(res & GSR_MISSING ? "missing;" : "").wx_str(), + wxString(res & GSR_EXCESS ? "excess;" : "").wx_str()); + } + } + } } void StaticExecute(u32 code)