rpcs3/rpcs3/Emu/SysCalls/Modules/libmixer.cpp
Arkaran99 3caff5a107 Change ModuleManager::init function.
First step to help refactor Module management.
Add every module in the static ModuleInfo list. Module without id are assigned
to 0xffff.
The init function is called after constructor and take a pointer to Module
as an input.
This pointer is used to set the Module's global pointer in its file.
2014-09-13 22:00:17 +02:00

1212 lines
29 KiB
C++

#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Callback.h"
#include "Emu/CPU/CPUThreadManager.h"
#include "Emu/Audio/cellAudio.h"
#include "libmixer.h"
Module *libmixer = nullptr;
CellSurMixerConfig surMixer;
#define SUR_PORT (7)
vm::ptr<CellSurMixerNotifyCallbackFunction> surMixerCb;
vm::ptr<void> surMixerCbArg;
std::mutex mixer_mutex;
float mixdata[8*256];
u64 mixcount;
std::vector<SSPlayer> ssp;
int cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, vm::ptr<float> addr, u32 samples)
{
libmixer->Log("cellAANAddData(handle=%d, port=%d, offset=0x%x, addr=0x%x, samples=%d)",
aan_handle, aan_port, offset, addr.addr(), samples);
u32 type = aan_port >> 16;
u32 port = aan_port & 0xffff;
switch (type)
{
case CELL_SURMIXER_CHSTRIP_TYPE1A:
if (port >= surMixer.chStrips1) type = 0; break;
case CELL_SURMIXER_CHSTRIP_TYPE2A:
if (port >= surMixer.chStrips2) type = 0; break;
case CELL_SURMIXER_CHSTRIP_TYPE6A:
if (port >= surMixer.chStrips6) type = 0; break;
case CELL_SURMIXER_CHSTRIP_TYPE8A:
if (port >= surMixer.chStrips8) type = 0; break;
default:
type = 0; break;
}
if (aan_handle != 0x11111111 || samples != 256 || !type || offset != 0)
{
libmixer->Error("cellAANAddData(handle=%d, port=%d, offset=0x%x, addr=0x%x, samples=%d): invalid parameters",
aan_handle, aan_port, offset, addr, samples);
return CELL_LIBMIXER_ERROR_INVALID_PARAMATER;
}
std::lock_guard<std::mutex> lock(mixer_mutex);
if (type == CELL_SURMIXER_CHSTRIP_TYPE1A)
{
// mono upmixing
for (u32 i = 0; i < samples; i++)
{
const float center = addr[i];
mixdata[i * 8 + 0] += center;
mixdata[i * 8 + 1] += center;
}
}
else if (type == CELL_SURMIXER_CHSTRIP_TYPE2A)
{
// stereo upmixing
for (u32 i = 0; i < samples; i++)
{
const float left = addr[i * 2 + 0];
const float right = addr[i * 2 + 1];
mixdata[i * 8 + 0] += left;
mixdata[i * 8 + 1] += right;
}
}
else if (type == CELL_SURMIXER_CHSTRIP_TYPE6A)
{
// 5.1 upmixing
for (u32 i = 0; i < samples; i++)
{
const float left = addr[i * 6 + 0];
const float right = addr[i * 6 + 1];
const float center = addr[i * 6 + 2];
const float low_freq = addr[i * 6 + 3];
const float rear_left = addr[i * 6 + 4];
const float rear_right = addr[i * 6 + 5];
mixdata[i * 8 + 0] += left;
mixdata[i * 8 + 1] += right;
mixdata[i * 8 + 2] += center;
mixdata[i * 8 + 3] += low_freq;
mixdata[i * 8 + 4] += rear_left;
mixdata[i * 8 + 5] += rear_right;
}
}
else if (type == CELL_SURMIXER_CHSTRIP_TYPE8A)
{
// 7.1
for (u32 i = 0; i < samples * 8; i++)
{
mixdata[i] += addr[i];
}
}
return CELL_OK;
}
int cellAANConnect(u32 receive, u32 receivePortNo, u32 source, u32 sourcePortNo)
{
libmixer->Warning("cellAANConnect(receive=%d, receivePortNo=%d, source=%d, sourcePortNo=%d)",
receive, receivePortNo, source, sourcePortNo);
std::lock_guard<std::mutex> 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->Warning("cellAANDisconnect(receive=%d, receivePortNo=%d, source=%d, sourcePortNo=%d)",
receive, receivePortNo, source, sourcePortNo);
std::lock_guard<std::mutex> 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(vm::ptr<be_t<u32>> handle, vm::ptr<CellSSPlayerConfig> config)
{
libmixer->Warning("cellSSPlayerCreate(handle_addr=0x%x, config_addr=0x%x)",
handle.addr(), config.addr());
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<std::mutex> 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 = (u32)ssp.size() - 1;
return CELL_OK;
}
int cellSSPlayerRemove(u32 handle)
{
libmixer->Warning("cellSSPlayerRemove(handle=%d)", handle);
std::lock_guard<std::mutex> 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, vm::ptr<CellSSPlayerWaveParam> waveInfo, vm::ptr<CellSSPlayerCommonParam> commonInfo)
{
libmixer->Warning("cellSSPlayerSetWave(handle=%d, waveInfo_addr=0x%x, commonInfo_addr=0x%x)",
handle, waveInfo.addr(), commonInfo.addr());
std::lock_guard<std::mutex> 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 ? (u32)commonInfo->loopMode : CELL_SSPLAYER_ONESHOT;
ssp[handle].m_position = waveInfo->startOffset - 1;
return CELL_OK;
}
int cellSSPlayerPlay(u32 handle, vm::ptr<CellSSPlayerRuntimeInfo> info)
{
libmixer->Warning("cellSSPlayerPlay(handle=%d, info_addr=0x%x)", handle, info.addr());
std::lock_guard<std::mutex> 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->Warning("cellSSPlayerStop(handle=%d, mode=0x%x)", handle, mode);
std::lock_guard<std::mutex> 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, vm::ptr<CellSSPlayerRuntimeInfo> info)
{
libmixer->Warning("cellSSPlayerSetParam(handle=%d, info_addr=0x%x)", handle, info.addr());
std::lock_guard<std::mutex> 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;
}
int cellSSPlayerGetState(u32 handle)
{
libmixer->Warning("cellSSPlayerGetState(handle=%d)", handle);
std::lock_guard<std::mutex> 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(vm::ptr<const CellSurMixerConfig> config)
{
libmixer->Warning("cellSurMixerCreate(config_addr=0x%x)", config.addr());
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);
mixcount = 0;
surMixerCb.set(0);
thread t("Surmixer Thread", []()
{
AudioPortConfig& port = m_config.m_ports[SUR_PORT];
PPUThread& cb_thread = *(PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU);
cb_thread.SetName("Surmixer Callback Thread");
cb_thread.SetEntry(0);
cb_thread.SetPrio(1001);
cb_thread.SetStackSize(0x10000);
cb_thread.InitStack();
cb_thread.InitRegs();
cb_thread.DoRun();
while (port.m_is_audio_port_opened)
{
if (Emu.IsStopped())
{
libmixer->Warning("Surmixer aborted");
break;
}
if (mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
if (port.m_is_audio_port_started)
{
//u64 stamp0 = get_system_time();
memset(mixdata, 0, sizeof(mixdata));
if (surMixerCb)
{
surMixerCb.call(cb_thread, surMixerCbArg, mixcount, 256);
}
//u64 stamp1 = get_system_time();
{
std::lock_guard<std::mutex> lock(mixer_mutex);
for (auto& p : ssp) if (p.m_active && p.m_created)
{
auto v = vm::lptrl<s16>::make(p.m_addr); // 16-bit LE audio data
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
{
left = right = (float)v[pos] / 0x8000 * p.m_level;
}
else if (p.m_channels == 2) // get stereo data
{
left = (float)v[pos * 2 + 0] / 0x8000 * p.m_level;
right = (float)v[pos * 2 + 1] / 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 = vm::get_ptr<be_t<float>>(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<std::mutex> lock(mixer_mutex);
ssp.clear();
}
Emu.GetCPU().RemoveThread(cb_thread.GetId());
surMixerCb.set(0);
});
t.detach();
return CELL_OK;
}
int cellSurMixerGetAANHandle(vm::ptr<be_t<u32>> handle)
{
libmixer->Warning("cellSurMixerGetAANHandle(handle_addr=0x%x) -> %d", handle.addr(), 0x11111111);
*handle = 0x11111111;
return CELL_OK;
}
int cellSurMixerChStripGetAANPortNo(vm::ptr<be_t<u32>> port, u32 type, u32 index)
{
libmixer->Warning("cellSurMixerChStripGetAANPortNo(port_addr=0x%x, type=0x%x, index=0x%x) -> 0x%x", port.addr(), type, index, (type << 16) | index);
*port = (type << 16) | index;
return CELL_OK;
}
int cellSurMixerSetNotifyCallback(vm::ptr<CellSurMixerNotifyCallbackFunction> func, vm::ptr<void> arg)
{
libmixer->Warning("cellSurMixerSetNotifyCallback(func_addr=0x%x, arg=0x%x)", func.addr(), arg.addr());
if (surMixerCb)
{
libmixer->Error("cellSurMixerSetNotifyCallback: surMixerCb already set (addr=0x%x)", surMixerCb.addr());
}
surMixerCb = func;
surMixerCbArg = arg;
return CELL_OK;
}
int cellSurMixerRemoveNotifyCallback(vm::ptr<CellSurMixerNotifyCallbackFunction> func)
{
libmixer->Warning("cellSurMixerRemoveNotifyCallback(func_addr=0x%x)", func.addr());
if (surMixerCb.addr() != func.addr())
{
libmixer->Error("cellSurMixerRemoveNotifyCallback: surMixerCb had different value (addr=0x%x)", surMixerCb.addr());
}
else
{
surMixerCb.set(0);
}
return CELL_OK;
}
int cellSurMixerStart()
{
libmixer->Warning("cellSurMixerStart()");
AudioPortConfig& port = m_config.m_ports[SUR_PORT];
if (port.m_is_audio_port_opened)
{
port.m_is_audio_port_started = true;
}
return CELL_OK;
}
int cellSurMixerSetParameter(u32 param, float value)
{
declCPU();
libmixer->Todo("cellSurMixerSetParameter(param=0x%x, value=%f, FPR[1]=%f, FPR[2]=%f)", param, value, (float&)CPU.FPR[1], (float&)CPU.FPR[2]);
return CELL_OK;
}
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--;
}
return CELL_OK;
}
int cellSurMixerSurBusAddData(u32 busNo, u32 offset, u32 addr, u32 samples)
{
if (busNo < 8 && samples == 256 && offset == 0)
{
libmixer->Log("cellSurMixerSurBusAddData(busNo=%d, offset=0x%x, addr=0x%x, samples=%d)", busNo, offset, addr, samples);
}
else
{
libmixer->Todo("cellSurMixerSurBusAddData(busNo=%d, offset=0x%x, addr=0x%x, samples=%d)", busNo, offset, addr, samples);
return CELL_OK;
}
std::lock_guard<std::mutex> lock(mixer_mutex);
for (u32 i = 0; i < samples; i++)
{
// reverse byte order and mix
u32 v = vm::read32(addr + i * sizeof(float));
mixdata[i*8+busNo] += (float&)v;
}
return CELL_OK;
}
int cellSurMixerChStripSetParameter(u32 type, u32 index, vm::ptr<CellSurMixerChStripParam> param)
{
libmixer->Todo("cellSurMixerChStripSetParameter(type=%d, index=%d, param_addr=0x%x)", type, index, param.addr());
return CELL_OK;
}
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;
}
return CELL_OK;
}
int cellSurMixerGetCurrentBlockTag(vm::ptr<be_t<u64>> tag)
{
libmixer->Log("cellSurMixerGetCurrentBlockTag(tag_addr=0x%x)", tag.addr());
*tag = mixcount;
return CELL_OK;
}
int cellSurMixerGetTimestamp(u64 tag, vm::ptr<be_t<u64>> stamp)
{
libmixer->Log("cellSurMixerGetTimestamp(tag=0x%llx, stamp_addr=0x%x)", tag, stamp.addr());
*stamp = m_config.start_time + (tag) * 256000000 / 48000; // ???
return CELL_OK;
}
void cellSurMixerBeep(u32 arg)
{
libmixer->Todo("cellSurMixerBeep(arg=%d)", arg);
return;
}
void cellSurMixerUtilGetLevelFromDB(float dB)
{
// not hooked, probably unnecessary
libmixer->Todo("cellSurMixerUtilGetLevelFromDB(dB=%f)", dB);
declCPU();
(float&)CPU.FPR[0] = 0.0f;
}
void cellSurMixerUtilGetLevelFromDBIndex(int index)
{
// not hooked, probably unnecessary
libmixer->Todo("cellSurMixerUtilGetLevelFromDBIndex(index=%d)", index);
declCPU();
(float&)CPU.FPR[0] = 0.0f;
}
void cellSurMixerUtilNoteToRatio(u8 refNote, u8 note)
{
// not hooked, probably unnecessary
libmixer->Todo("cellSurMixerUtilNoteToRatio(refNote=%d, note=%d)", refNote, note);
declCPU();
(float&)CPU.FPR[0] = 0.0f;
}
void libmixer_init(Module *pxThis)
{
libmixer = pxThis;
REG_SUB(libmixer, "surmxAAN", cellAANAddData,
0xffffffff7c691b78,
0xffffffff7c0802a6,
0xfffffffff821ff91,
0xfffffffff8010080,
0xffffffff7c802378,
0xffffffff7caa2b78,
0xffffffff81690000,
0xffffffff7c050378,
0xffffffff7cc43378,
0x78630020, // clrldi r3,r3,32
0xffffffff7d465378,
0xffffffff812b0030,
0xffffffff80090000,
0xfffffffff8410028,
0xffffffff7c0903a6,
0xffffffff80490004,
0xffffffff4e800421,
0xffffffffe8410028,
0xffffffffe8010080,
0xffffffff7c6307b4,
0xffffffff7c0803a6,
0xffffffff38210070,
0xffffffff4e800020
);
REG_SUB(libmixer, "surmxAAN", cellAANConnect,
0xfffffffff821ff71,
0xffffffff7c0802a6,
0xffffffff2f830000,
0xfffffffff80100a0,
0xffffffff3c008031,
0xffffffff7c691b78,
0xffffffff7c8a2378,
0xffffffff60000003,
0xffffff00409e0018, // bne
0xffffffff7c0307b4,
0xffffffffe80100a0,
0xffffffff38210090,
0xffffffff7c0803a6,
0xffffffff4e800020,
0xffffffff2f850000,
0xffffffff78630020,
0xffffffff38810070,
0xffffff00419effe0, // beq
0xffffffff81690000,
0xffffffff38000001,
0xffffffff91210074,
0xffffffff90a10070,
0xffffffff90c10078,
0xffffffff9141007c,
0xffffffff812b0018, // difference
0xffffffff90010080,
0xffffffff80090000,
0xfffffffff8410028,
0xffffffff7c0903a6,
0xffffffff80490004,
0xffffffff4e800421,
0xffffffffe8410028,
0xffffffff7c601b78,
0xffffffff7c0307b4,
0xffffffffe80100a0,
0xffffffff38210090,
0xffffffff7c0803a6,
0xffffffff4e800020
);
REG_SUB(libmixer, "surmxAAN", cellAANDisconnect,
0xfffffffff821ff71,
0xffffffff7c0802a6,
0xffffffff2f830000,
0xfffffffff80100a0,
0xffffffff3c008031,
0xffffffff7c691b78,
0xffffffff7c8a2378,
0xffffffff60000003,
0xffffff00409e0018, // bne
0xffffffff7c0307b4,
0xffffffffe80100a0,
0xffffffff38210090,
0xffffffff7c0803a6,
0xffffffff4e800020,
0xffffffff2f850000,
0xffffffff78630020,
0xffffffff38810070,
0xffffff00419effe0, // beq
0xffffffff81690000,
0xffffffff38000001,
0xffffffff91210074,
0xffffffff90a10070,
0xffffffff90c10078,
0xffffffff9141007c,
0xffffffff812b001c, // difference
0xffffffff90010080,
0xffffffff80090000,
0xfffffffff8410028,
0xffffffff7c0903a6,
0xffffffff80490004,
0xffffffff4e800421,
0xffffffffe8410028,
0xffffffff7c601b78,
0xffffffff7c0307b4,
0xffffffffe80100a0,
0xffffffff38210090,
0xffffffff7c0803a6,
0xffffffff4e800020
);
REG_SUB(libmixer, "surmixer", cellSurMixerCreate,
0xffffffff2f830000,
0xffffffff7c0802a6,
0xfffffffff821ff51,
0xfffffffffbc100a0,
0xfffffffffb210078,
0xfffffffffb410080,
0xfffffffffb610088,
0xfffffffffb810090,
0xfffffffffba10098,
0xfffffffffbe100a8,
0xfffffffff80100c0,
0xffffffff7c7e1b78,
0xf000000040000000, // bne
0xffffffff3fe08031,
0xffffffff63ff0003,
0xffffffffe80100c0,
0xffffffff7fe307b4,
0xffffffffeb210078,
0xffffffffeb410080,
0xffffffff7c0803a6,
0xffffffffeb610088,
0xffffffffeb810090,
0xffffffffeba10098,
0xffffffffebc100a0,
0xffffffffebe100a8,
0xffffffff382100b0
);
REG_SUB(libmixer, "surmixer", cellSurMixerGetAANHandle,
0xff00000081428250, // lwz
0xffffffff3d607fce,
0xffffffff616bfffe,
0xffffffff812a0018,
0xffffffff7d2afe70,
0xffffffff91230000,
0xffffffff7d404a78,
0xffffffff7c005050,
0xffffffff7c00fe70,
0xffffffff7c035838,
0xffffffff3c638031,
0xffffffff38630002,
0xffffffff7c6307b4,
0xffffffff4e800020
);
REG_SUB(libmixer, "surmixer", cellSurMixerChStripGetAANPortNo,
0xff00000081228250, // lwz
0xffffffff7c661b78,
0xffffffff3c608031,
0xffffffff78c60020,
0xffffffff78840020,
0xffffffff60630002,
0xffffffff80090018,
0xffffffff78a50020,
0xffffffff2f800000,
0xffffffff4d9e0020,
0xffffffff78030020,
0xf000000040000000 // b
);
REG_SUB(libmixer, "surmixer", cellSurMixerSetNotifyCallback,
0xff00000081428250, // lwz
0xffffffff7c0802a6,
0xfffffffff821ff81,
0xfffffffff8010090,
0xffffffff7c6b1b78,
0xffffffff3c608031,
0xffffffff812a0018,
0xffffffff7c882378,
0xffffffff60630003,
0xffffffff2f890000,
0xffffffff2f0b0000,
0xffffff00409e0020, // bne
0xffffffff3c608031,
0xffffffff60630002,
0xffffffffe8010090,
0xffffffff7c6307b4,
0xffffffff38210080,
0xffffffff7c0803a6,
0xffffffff4e800020,
0xffffff00419affec, // beq
0xf0000000800a001c, // lwz
0xffffffff79290020,
0xffffffff38810070,
0xffffffff2f800000,
0xffffffff7d234b78
);
REG_SUB(libmixer, "surmixer", cellSurMixerRemoveNotifyCallback,
0xff00000081628250, // lwz
0xffffffff7c0802a6,
0xfffffffff821ff81,
0xfffffffff8010090,
0xffffffff7c6a1b78,
0xffffffff3d208031,
0xffffffff806b0018,
0xffffffff61290002, // ori
0xffffffff2f830000,
0xffff0000409e0018, // bne
0xffffffffe8010090,
0xffffffff7d2307b4,
0xffffffff38210080,
0xffffffff7c0803a6,
0xffffffff4e800020
);
REG_SUB(libmixer, "surmixer", cellSurMixerStart,
0xfffffffff821ff71,
0xffffffff7c0802a6,
0xfffffffffbc10080,
0xf000000083c20000, // lwz
0xfffffffff80100a0,
0xfffffffffba10078,
0xfffffffffbe10088,
0xffffffff801e0018,
0xffffffff2f800000,
0xf0000000409e002c, // bne
0xffffffff3fe08031,
0xffffffff63ff0002,
0xffffffffe80100a0,
0xffffffff7fe307b4,
0xffffffffeba10078,
0xffffffffebc10080,
0xffffffff7c0803a6,
0xffffffffebe10088,
0xffffffff38210090,
0xffffffff4e800020
);
REG_SUB(libmixer, "surmixer", cellSurMixerSetParameter,
0xfffffffff821ff81,
0xffffffff7c0802a6,
0xfffffffffbc10070,
0xfffffffffc000890,
0xf000000083c28250, // lwz
0xffffffff3d208031,
0xfffffffff8010090,
0xfffffffffbe10078,
0xffffffff61290002,
0xffffffff7c7f1b78,
0xffffffff801e0018,
0xffffffff2f800000,
0xffff0000409e0020, // bne
0xffffffffe8010090,
0xffffffff7d2307b4,
0xffffffffebc10070,
0xffffffffebe10078,
0xffffffff7c0803a6,
0xffffffff38210080,
0xffffffff4e800020,
0xffffffff801e001c,
0xffffffff2b03001f,
0xffffffff2f800000,
0xffff0000419cffd8, // blt
0xffffffff2b83002b,
0xffff000040990008, // ble
0xffff0000409d0054 // ble
);
REG_SUB(libmixer, "surmixer", cellSurMixerFinalize,
0xfffffffff821ff91,
0xffffffff7c0802a6,
0xfffffffff8010080,
0xffffff004bfffde1, // bl
0xffffffffe8010080,
0xffffffff38600000,
0xffffffff38210070,
0xffffffff7c0803a6,
0xffffffff4e800020,
0xfffffffff821ff71,
0xffffffff7c0802a6,
0xfffffffffba10078,
0xf000000083a28250, // lwz
0xfffffffff80100a0,
0xffffffff817d0018,
0xffffffff7d635b78,
0xffffffff812b0000,
0xffffffff81490000,
0xffffffff800a0000,
0xfffffffff8410028,
0xffffffff7c0903a6,
0xffffffff804a0004,
0xffffffff4e800421
);
REG_SUB(libmixer, "surmixer", cellSurMixerSurBusAddData,
0xff00000081428250, // lwz
0xffffffff7c0802a6,
0xfffffffff821ff91,
0xfffffffff8010080,
0xffffffff7c601b78,
0xffffffff3d208031,
0xffffffff806a0018,
0xffffffff7c8b2378,
0xffffffff7cc73378,
0xffffffff2f830000,
0xffffffff61290002,
0xffff0000409e0018, // bne
0xffffffffe8010080,
0xffffffff7d2307b4,
0xffffffff38210070,
0xffffffff7c0803a6,
0xffffffff4e800020,
0xffffffff78a40020,
0xffffffff78050020,
0xffffffff800a001c,
0xffffffff78680020,
0xffffffff2f800000,
0xffffffff7d034378,
0xffffffff79660020,
0xffffffff78e70020,
0xffff0000419cffcc // blt
);
REG_SUB(libmixer, "surmixer", cellSurMixerChStripSetParameter,
0xff00000081028250, // lwz
0xffffffff7c6b1b78,
0xffffffff3c608031,
0xffffffff7c8a2378,
0xffffffff7ca62b78,
0xffffffff60630002,
0xffffffff81280018,
0xffffffff2f890000,
0xffff00004d9e0020, // beqlr
0xffffffff8008001c,
0xffffffff79640020,
0xffffffff79450020,
0xffffffff2f800000,
0xffffffff78c60020,
0xffffffff4d9c0020,
0xffffffff79230020,
0xf000000048000000 // b
);
REG_SUB(libmixer, "surmixer", cellSurMixerPause,
0xff00000081428250, // lwz
0xffffffff7c0802a6,
0xfffffffff821ff81,
0xfffffffff8010090,
0xffffffff3d208031,
0xfffffffffbe10078,
0xffffffff800a0018,
0xffffffff7c7f1b78,
0xfffffffffbc10070,
0xffffffff2f800000,
0xffffffff61290002,
0xffff0000409e0020, // bne
0xffffffffe8010090,
0xffffffff7d2307b4,
0xffffffffebc10070,
0xffffffffebe10078,
0xffffffff7c0803a6,
0xffffffff38210080,
0xffffffff4e800020,
0xffffffff800a001c,
0xffffffff2b030002,
0xffffffff2f800000
);
REG_SUB(libmixer, "surmixer", cellSurMixerGetCurrentBlockTag,
0xff00000081628250, // lwz
0xffffffff3d208031,
0xffffffff61290002,
0xffffffff880b0020,
0xffffffff2f800000,
0xffff0000419e0010, // beq
0xffffffffe80b0028,
0xffffffff39200000,
0xfffffffff8030000,
0xffffffff7d2307b4,
0xffffffff4e800020
);
REG_SUB(libmixer, "surmixer", cellSurMixerGetTimestamp,
0xff00000081628250, // lwz
0xffffffff7c0802a6,
0xfffffffff821ff91,
0xfffffffff8010080,
0xffffffff7c852378,
0xffffffff3d208031,
0xffffffff880b0020,
0xffffffff7c641b78,
0xffffffff78a50020,
0xffffffff2f800000,
0xffffffff61290002,
0xffff000040de0018, // bne-
0xffffffffe8010080,
0xffffffff7d2307b4,
0xffffffff38210070,
0xffffffff7c0803a6,
0xffffffff4e800020,
0xffffffff806b04d8,
0xf000000048000001 // bl
);
REG_SUB(libmixer, "surmixer", cellSurMixerBeep,
0xff00000081228250, // lwz
0xffffffff7c641b78,
0xffffffff80690018,
0xffffffff2f830000,
0xffff00004d9e0020, // beqlr
0xffffffff8009001c,
0xffffffff78630020,
0xffffffff78840020,
0xffffffff2f800000,
0xffffffff4d9c0020,
0xf000000048000000 // b
);
REG_SUB(libmixer, "surmxSSP", cellSSPlayerCreate,
0xfffffffff821ff51,
0xffffffff7c0802a6,
0xffffffff2f840000,
0xfffffffff80100c0,
0xffffffff3c008031,
0xfffffffffb210078,
0xfffffffffb410080,
0xfffffffffb610088,
0xfffffffffb810090,
0xfffffffffba10098,
0xfffffffffbc100a0,
0xfffffffffbe100a8,
0xffffffff7c9a2378,
0xffffffff7c791b78,
0xffffffff60000003,
0xffff0000419e0068, // beq
0xff00000083620000, // lwz
0xffffffff3b800000,
0xffffffff381b0064,
0xffffffff901b0018,
0xffffffff5780103a,
0xffffffff38800010,
0xffffffff7c0007b4,
0xffffffff38a01c70,
0xffffffff7fc0da14,
0xffffffff38c00000,
0xffffffff83be0024,
0xffffffff2f9d0000,
0xffffffff7ba30020,
0xffff000041de00c0, // beq-
0xf000000048000001 // bl
);
REG_SUB(libmixer, "surmxSSP", cellSSPlayerRemove,
0xffffffff7c641b78,
0xffffffff7c0802a6,
0xffffffff3c608031,
0xffffffff2f840000,
0xfffffffff821ff51,
0xfffffffffb010070,
0xfffffffffb210078,
0xfffffffffb410080,
0xfffffffffb610088,
0xfffffffffb810090,
0xfffffffffba10098,
0xfffffffffbc100a0,
0xfffffffffbe100a8,
0xfffffffff80100c0,
0xffffffff60630003,
0xffff0000419e0074, // beq
0xffffffff81240000,
0xffffffff78830020,
0xffffffff83440004,
0xffffffff83240008,
0xffffffff7b5b0020,
0xffffffff81690000,
0xffffffff800b0000,
0xfffffffff8410028,
0xffffffff7c0903a6,
0xffffffff804b0004,
0xffffffff4e800421
);
REG_SUB(libmixer, "surmxSSP", cellSSPlayerSetWave,
0xffffffff7c601b78,
0xffffffff78840020,
0xffffffff2f800000,
0xffffffff3c608031,
0xffffffff78a50020,
0xffff0000419e000c, // beq
0xffffffff78030020,
0xf000000048000000, // b
0xffffffff60630003,
0xffffffff4e800020
);
REG_SUB(libmixer, "surmxSSP", cellSSPlayerPlay,
0xffffffff7c601b78,
0xffffffff3c608031,
0xffffffff2f800000,
0xffffffff60630003,
0xffffffff78840020,
0xffffffff4d9e0020,
0xffffffff78030020,
0xf000000048000000, // b
0xfffffffff821ff81, // next func
0xffffffff7c0802a6,
0xfffffffffbe10078,
0xffffffff7c7f1b78,
0xff00000081620028, // lwz
0xfffffffff8010090,
0xffffffff39400000,
0xffffffff38630010
);
REG_SUB(libmixer, "surmxSSP", cellSSPlayerStop,
0xfffffffff821ff91,
0xffffffff7c0802a6,
0xffffffff2f830000,
0xfffffffff8010080,
0xffffffff3c008031,
0xffffffff78630020,
0xffffffff60000003,
0xffff0000419e0010, // beq
0xffffffff78840020,
0xf000000048000001, // bl
0xffffffff38000000,
0xffffffff7c0307b4,
0xffffffffe8010080,
0xffffffff38210070,
0xffffffff7c0803a6,
0xffffffff4e800020
);
REG_SUB(libmixer, "surmxSSP", cellSSPlayerSetParam,
0xffffffff7c601b78,
0xffffffff3c608031,
0xffffffff2f800000,
0xffffffff60630003,
0xffffffff78840020,
0xffffffff4d9e0020,
0xffffffff78030020,
0xf000000048000000, // b
0xfffffffff821ff71, // next func
0xffffffff7c0802a6,
0xffffffff3d608031,
0xfffffffff80100a0,
0xffffffff80030068,
0xffffffff616b0002,
0xfffffffffbc10080,
0xffffffff2f800000
);
REG_SUB(libmixer, "surmxSSP", cellSSPlayerGetState,
0xffffffff7c601b78,
0xffffffff3c608031,
0xffffffff2f800000,
0xffffffff60630003,
0xffffffff4d9e0020,
0xffffffff78030020,
0xf000000048000000 // b
);
REG_SUB(libmixer, "surmxUti", cellSurMixerUtilGetLevelFromDB, 0);
REG_SUB(libmixer, "surmxUti", cellSurMixerUtilGetLevelFromDBIndex, 0);
REG_SUB(libmixer, "surmxUti", cellSurMixerUtilNoteToRatio, 0);
}