From 60f3ed3543b5854b9a062c35140ea50a552fbb90 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sat, 5 Jul 2014 23:24:14 +0400 Subject: [PATCH] SSPlayer funcs in libmixer --- rpcs3/Emu/SysCalls/Modules/libmixer.cpp | 426 +++++++++++++++++++----- rpcs3/Emu/SysCalls/Modules/libmixer.h | 22 +- 2 files changed, 360 insertions(+), 88 deletions(-) diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp index 18618ff190..dc588d5d7e 100644 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp @@ -21,8 +21,13 @@ std::mutex mixer_mutex; float mixdata[8*256]; u64 mixcount = 0; +std::vector ssp; + int cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, u32 addr, u32 samples) { + libmixer->Log("cellAANAddData(handle=%d, port=%d, offset=0x%x, addr=0x%x, samples=%d)", + aan_handle, aan_port, offset, addr, samples); + u32 type = aan_port >> 16; u32 port = aan_port & 0xffff; @@ -40,17 +45,11 @@ int cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, u32 addr, u32 sampl type = 0; break; } - if (aan_handle == 0x11111111 && samples == 256 && type && offset == 0) + if (aan_handle != 0x11111111 || samples != 256 || !type || offset != 0) { - libmixer->Log("cellAANAddData(handle=0x%x, port=0x%x, offset=0x%x, addr=0x%x, samples=0x%x)", + libmixer->Error("cellAANAddData(handle=%d, port=%d, offset=0x%x, addr=0x%x, samples=%d): invalid parameters", 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; + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; } std::lock_guard lock(mixer_mutex); @@ -109,74 +108,386 @@ int cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, u32 addr, u32 sampl int cellAANConnect(u32 receive, u32 receivePortNo, u32 source, u32 sourcePortNo) { - libmixer->Error("cellAANConnect(receive=0x%x, receivePortNo=0x%x, source=0x%x, sourcePortNo=0x%x)", + libmixer->Warning("cellAANConnect(receive=%d, receivePortNo=%d, source=%d, sourcePortNo=%d)", receive, receivePortNo, source, sourcePortNo); + + std::lock_guard lock(mixer_mutex); + + if (source >= ssp.size() || !ssp[source].m_created) + { + libmixer->Error("cellAANConnect(): invalid source (%d)", source); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + ssp[source].m_connected = true; + return CELL_OK; } int cellAANDisconnect(u32 receive, u32 receivePortNo, u32 source, u32 sourcePortNo) { - libmixer->Error("cellAANDisconnect(receive=0x%x, receivePortNo=0x%x, source=0x%x, sourcePortNo=0x%x)", + libmixer->Warning("cellAANDisconnect(receive=%d, receivePortNo=%d, source=%d, sourcePortNo=%d)", receive, receivePortNo, source, sourcePortNo); + + std::lock_guard lock(mixer_mutex); + + if (source >= ssp.size() || !ssp[source].m_created) + { + libmixer->Error("cellAANDisconnect(): invalid source (%d)", source); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + ssp[source].m_connected = false; + return CELL_OK; } int cellSSPlayerCreate(mem32_t handle, mem_ptr_t config) { - libmixer->Error("cellSSPlayerCreate(handle_addr=0x%x, config_addr=0x%x)", + libmixer->Warning("cellSSPlayerCreate(handle_addr=0x%x, config_addr=0x%x)", handle.GetAddr(), config.GetAddr()); + + if (!config.IsGood()) + { + return CELL_EFAULT; + } + + if (config->outputMode != 0 || config->channels - 1 >= 2) + { + libmixer->Error("cellSSPlayerCreate(config.outputMode=%d, config.channels=%d): invalid parameters", + (u32)config->outputMode, (u32)config->channels); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + std::lock_guard lock(mixer_mutex); + + SSPlayer p; + p.m_created = true; + p.m_connected = false; + p.m_active = false; + p.m_channels = config->channels; + + ssp.push_back(p); + handle = ssp.size() - 1; return CELL_OK; } int cellSSPlayerRemove(u32 handle) { - libmixer->Error("cellSSPlayerRemove(handle=%d)", handle); + libmixer->Warning("cellSSPlayerRemove(handle=%d)", handle); + + std::lock_guard lock(mixer_mutex); + + if (handle >= ssp.size() || !ssp[handle].m_created) + { + libmixer->Error("cellSSPlayerRemove(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + ssp[handle].m_active = false; + ssp[handle].m_created = false; + ssp[handle].m_connected = false; + return CELL_OK; } int cellSSPlayerSetWave(u32 handle, mem_ptr_t waveInfo, mem_ptr_t commonInfo) { - libmixer->Error("cellSSPlayerSetWave(handle=%d, waveInfo_addr=0x%x, commonInfo_addr=0x%x)", + libmixer->Warning("cellSSPlayerSetWave(handle=%d, waveInfo_addr=0x%x, commonInfo_addr=0x%x)", handle, waveInfo.GetAddr(), commonInfo.GetAddr()); + + if (!waveInfo.IsGood() || (commonInfo.GetAddr() && !commonInfo.IsGood())) + { + return CELL_EFAULT; + } + + std::lock_guard lock(mixer_mutex); + + if (handle >= ssp.size() || !ssp[handle].m_created) + { + libmixer->Error("cellSSPlayerSetWave(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + // TODO: check parameters + + ssp[handle].m_addr = waveInfo->addr; + ssp[handle].m_samples = waveInfo->samples; + ssp[handle].m_loop_start = waveInfo->loopStartOffset - 1; + ssp[handle].m_loop_mode = commonInfo.GetAddr() ? commonInfo->loopMode : CELL_SSPLAYER_ONESHOT; + ssp[handle].m_position = waveInfo->startOffset - 1; + return CELL_OK; } int cellSSPlayerPlay(u32 handle, mem_ptr_t info) { - libmixer->Error("cellSSPlayerPlay(handle=%d, info_addr=0x%x)", handle, info.GetAddr()); + libmixer->Warning("cellSSPlayerPlay(handle=%d, info_addr=0x%x)", handle, info.GetAddr()); + + if (!info.IsGood()) + { + return CELL_EFAULT; + } + + std::lock_guard lock(mixer_mutex); + + if (handle >= ssp.size() || !ssp[handle].m_created) + { + libmixer->Error("cellSSPlayerPlay(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + // TODO: check parameters + + ssp[handle].m_active = true; + ssp[handle].m_level = info->level; + ssp[handle].m_speed = info->speed; + ssp[handle].m_x = info->position.x; + ssp[handle].m_y = info->position.y; + ssp[handle].m_z = info->position.z; + return CELL_OK; } int cellSSPlayerStop(u32 handle, u32 mode) { - libmixer->Error("cellSSPlayerStop(handle=%d, mode=0x%x)", handle, mode); + libmixer->Warning("cellSSPlayerStop(handle=%d, mode=0x%x)", handle, mode); + + std::lock_guard lock(mixer_mutex); + + if (handle >= ssp.size() || !ssp[handle].m_created) + { + libmixer->Error("cellSSPlayerStop(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + // TODO: transition to stop state + + ssp[handle].m_active = false; + return CELL_OK; } int cellSSPlayerSetParam(u32 handle, mem_ptr_t info) { - libmixer->Error("cellSSPlayerSetParam(handle=%d, info_addr=0x%x)", handle, info.GetAddr()); + libmixer->Warning("cellSSPlayerSetParam(handle=%d, info_addr=0x%x)", handle, info.GetAddr()); + + if (!info.IsGood()) + { + return CELL_EFAULT; + } + + std::lock_guard lock(mixer_mutex); + + if (handle >= ssp.size() || !ssp[handle].m_created) + { + libmixer->Error("cellSSPlayerSetParam(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + // TODO: check parameters + + ssp[handle].m_level = info->level; + ssp[handle].m_speed = info->speed; + ssp[handle].m_x = info->position.x; + ssp[handle].m_y = info->position.y; + ssp[handle].m_z = info->position.z; + return CELL_OK; } -s32 cellSSPlayerGetState(u32 handle) +int cellSSPlayerGetState(u32 handle) { - libmixer->Error("cellSSPlayerGetState(handle=%d) -> OFF", handle); + libmixer->Warning("cellSSPlayerGetState(handle=%d)", handle); + + std::lock_guard lock(mixer_mutex); + + if (handle >= ssp.size() || !ssp[handle].m_created) + { + libmixer->Warning("cellSSPlayerGetState(): SSPlayer not found (%d)", handle); + return CELL_SSPLAYER_STATE_ERROR; + } + + if (ssp[handle].m_active) + { + return CELL_SSPLAYER_STATE_ON; + } + return CELL_SSPLAYER_STATE_OFF; } int cellSurMixerCreate(const mem_ptr_t config) { libmixer->Warning("cellSurMixerCreate(config_addr=0x%x)", config.GetAddr()); + surMixer = *config; + + AudioPortConfig& port = m_config.m_ports[SUR_PORT]; + + if (port.m_is_audio_port_opened) + { + return CELL_LIBMIXER_ERROR_FULL; + } + + port.channel = 8; + port.block = 16; + port.attr = 0; + port.level = 1.0f; + + 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); + + thread t("Surmixer Thread", []() + { + AudioPortConfig& port = m_config.m_ports[SUR_PORT]; + + CPUThread* mixerCb = &Emu.GetCPU().AddThread(CPU_THREAD_PPU); + + mixerCb->SetName("Surmixer Callback"); + + mixcount = 0; + + while (port.m_is_audio_port_opened) + { + if (Emu.IsStopped()) + { + LOG_WARNING(HLE, "Surmixer aborted"); + break; + } + + if (mixcount > (port.tag + 15)) // preemptive buffer filling (probably hack) + { + Sleep(1); + continue; + } + + if (port.m_is_audio_port_started) + { + u64 stamp0 = get_system_time(); + + memset(mixdata, 0, sizeof(mixdata)); + if (surMixerCb) mixerCb->ExecAsCallback(surMixerCb, true, surMixerCbArg, mixcount, 256); + + u64 stamp1 = get_system_time(); + + { + std::lock_guard lock(mixer_mutex); + + for (auto& p : ssp) if (p.m_active && p.m_created) + { + float left = 0.0f; + float right = 0.0f; + float speed = fabs(p.m_speed); + float fpos = 0.0f; + for (int i = 0; i < 256; i++) if (p.m_active) + { + u32 pos = p.m_position; + int pos_inc = 0; + if (p.m_speed > 0.0f) // select direction + { + pos_inc = 1; + } + else if (p.m_speed < 0.0f) + { + pos_inc = -1; + } + int shift = i - (int)fpos; // change playback speed (simple and rough) + if (shift > 0) + { + // slow playback + pos_inc = 0; // duplicate one sample at this time + fpos += 1.0f; + fpos += speed; + } + else if (shift < 0) + { + // fast playback + i--; // mix two sample into one at this time + fpos -= 1.0f; + } + else + { + fpos += speed; + } + p.m_position += (u32)pos_inc; + if (p.m_channels == 1) // get mono data + { + mem16_t v(p.m_addr + pos * sizeof(u16)); + left = right = (float)(s16)re16(v.GetValue()) / 0x8000 * p.m_level; + } + else if (p.m_channels == 2) // get stereo data + { + mem16_t v1(p.m_addr + (pos * 2 + 0) * sizeof(u16)); + mem16_t v2(p.m_addr + (pos * 2 + 1) * sizeof(u16)); + left = (float)(s16)re16(v1.GetValue()) / 0x8000 * p.m_level; + right = (float)(s16)re16(v2.GetValue()) / 0x8000 * p.m_level; + } + if (p.m_connected) // mix + { + // TODO: m_x, m_y, m_z ignored + mixdata[i * 8 + 0] += left; + mixdata[i * 8 + 1] += right; + } + if ((p.m_position == p.m_samples && p.m_speed > 0.0f) || + (p.m_position == ~0 && p.m_speed < 0.0f)) // loop or stop + { + if (p.m_loop_mode == CELL_SSPLAYER_LOOP_ON) + { + p.m_position = p.m_loop_start; + } + else if (p.m_loop_mode == CELL_SSPLAYER_ONESHOT_CONT) + { + p.m_position -= (u32)pos_inc; // restore position + } + else // oneshot + { + p.m_active = false; + p.m_position = p.m_loop_start; // TODO: check value + } + } + } + } + } + + u64 stamp2 = get_system_time(); + + auto buf = (be_t*)&Memory[m_config.m_buffer + (128 * 1024 * SUR_PORT) + (mixcount % port.block) * port.channel * 256 * sizeof(float)]; + + for (u32 i = 0; i < (sizeof(mixdata) / sizeof(float)); i++) + { + // reverse byte order + buf[i] = mixdata[i]; + } + + u64 stamp3 = get_system_time(); + + //ConLog.Write("Libmixer perf: start=%lld (cb=%lld, ssp=%lld, finalize=%lld)", stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2); + } + + mixcount++; + } + + { + std::lock_guard lock(mixer_mutex); + ssp.clear(); + } + + Emu.GetCPU().RemoveThread(mixerCb->GetId()); + }); + t.detach(); + return CELL_OK; } int cellSurMixerGetAANHandle(mem32_t handle) { - libmixer->Warning("cellSurMixerGetAANHandle(handle_addr=0x%x) -> 0x11111111", handle.GetAddr()); + libmixer->Warning("cellSurMixerGetAANHandle(handle_addr=0x%x) -> %d", handle.GetAddr(), 0x11111111); handle = 0x11111111; return CELL_OK; } @@ -212,72 +523,9 @@ int cellSurMixerStart() if (port.m_is_audio_port_opened) { - return CELL_LIBMIXER_ERROR_FULL; + port.m_is_audio_port_started = true; } - port.channel = 8; - port.block = 16; - port.attr = 0; - port.level = 1.0f; - - libmixer->Warning("*** audio port opened(default)"); - - 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("Surmixer Thread", []() - { - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; - - CPUThread* mixerCb = &Emu.GetCPU().AddThread(CPU_THREAD_PPU); - - mixerCb->SetName("Surmixer Callback"); - - mixcount = 0; - - while (port.m_is_audio_port_started) - { - if (Emu.IsStopped()) - { - LOG_WARNING(HLE, "Surmixer aborted"); - return; - } - - if (mixcount > (port.tag + 15)) // preemptive buffer filling (probably hack) - { - Sleep(1); - continue; - } - - u64 stamp0 = get_system_time(); - - memset(mixdata, 0, sizeof(mixdata)); - mixerCb->ExecAsCallback(surMixerCb, true, surMixerCbArg, mixcount, 256); - - u64 stamp1 = get_system_time(); - - auto buf = (be_t*)&Memory[m_config.m_buffer + (128 * 1024 * SUR_PORT) + (mixcount % port.block) * port.channel * 256 * sizeof(float)]; - - for (u32 i = 0; i < (sizeof(mixdata) / sizeof(float)); i++) - { - // reverse byte order - buf[i] = mixdata[i]; - } - - u64 stamp2 = get_system_time(); - - //ConLog.Write("Libmixer perf: start=%d (cb=%d, finalize=%d)", - //stamp0 - m_config.start_time, stamp1-stamp0, stamp2-stamp1); - - mixcount++; - } - - Emu.GetCPU().RemoveThread(mixerCb->GetId()); - }); - t.detach(); - return CELL_OK; } @@ -336,7 +584,15 @@ int cellSurMixerChStripSetParameter(u32 type, u32 index, mem_ptr_tError("cellSurMixerPause(type=%d)", 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; + } + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.h b/rpcs3/Emu/SysCalls/Modules/libmixer.h index 649dcda2f7..c5cac3baf2 100644 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.h +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.h @@ -119,7 +119,7 @@ struct CellSSPlayerConfig struct CellSSPlayerWaveParam { - void *addr; + be_t addr; be_t format; be_t samples; be_t loopStartOffset; @@ -158,10 +158,26 @@ struct CellSurMixerConfig struct CellSurMixerChStripParam { be_t param; - void *attribute; + be_t attribute_addr; be_t dBSwitch; be_t floatVal; be_t intVal; }; -CellSSPlayerWaveParam current_SSPlayerWaveParam; \ No newline at end of file +struct SSPlayer +{ + bool m_created; // SSPlayerCreate/Remove + bool m_connected; // AANConnect/Disconnect + bool m_active; // SSPlayerPlay/Stop + u32 m_channels; // 1 or 2 + u32 m_addr; + u32 m_samples; + u32 m_loop_start; + u32 m_loop_mode; + u32 m_position; + float m_level; + float m_speed; + float m_x; + float m_y; + float m_z; +}; \ No newline at end of file