mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-25 04:02:42 +01:00
cellAudio, thread_t improvements, pause/resume callback
This commit is contained in:
parent
4dae27c1d4
commit
b897a5d20a
@ -537,16 +537,32 @@ bool ThreadBase::TestDestroy() const
|
||||
return m_destroy;
|
||||
}
|
||||
|
||||
thread_t::thread_t(const std::string& name, std::function<void()> func) : m_name(name), m_state(TS_NON_EXISTENT)
|
||||
thread_t::thread_t(const std::string& name, bool autojoin, std::function<void()> func)
|
||||
: m_name(name)
|
||||
, m_state(TS_NON_EXISTENT)
|
||||
, m_autojoin(autojoin)
|
||||
{
|
||||
start(func);
|
||||
}
|
||||
|
||||
thread_t::thread_t(const std::string& name) : m_name(name), m_state(TS_NON_EXISTENT)
|
||||
thread_t::thread_t(const std::string& name, std::function<void()> func)
|
||||
: m_name(name)
|
||||
, m_state(TS_NON_EXISTENT)
|
||||
, m_autojoin(false)
|
||||
{
|
||||
start(func);
|
||||
}
|
||||
|
||||
thread_t::thread_t(const std::string& name)
|
||||
: m_name(name)
|
||||
, m_state(TS_NON_EXISTENT)
|
||||
, m_autojoin(false)
|
||||
{
|
||||
}
|
||||
|
||||
thread_t::thread_t() : m_state(TS_NON_EXISTENT)
|
||||
thread_t::thread_t()
|
||||
: m_state(TS_NON_EXISTENT)
|
||||
, m_autojoin(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -559,7 +575,14 @@ thread_t::~thread_t()
|
||||
{
|
||||
if (m_state == TS_JOINABLE)
|
||||
{
|
||||
m_thr.detach();
|
||||
if (m_autojoin)
|
||||
{
|
||||
m_thr.join();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_thr.detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -717,6 +740,9 @@ void waiter_map_t::notify(u64 signal_id)
|
||||
}
|
||||
}
|
||||
|
||||
static const std::function<bool()> SQUEUE_ALWAYS_EXIT = [](){ return true; };
|
||||
static const std::function<bool()> SQUEUE_NEVER_EXIT = [](){ return false; };
|
||||
|
||||
bool squeue_test_exit()
|
||||
{
|
||||
return Emu.IsStopped();
|
||||
|
@ -65,8 +65,10 @@ class thread_t
|
||||
std::atomic<thread_state_t> m_state;
|
||||
std::string m_name;
|
||||
std::thread m_thr;
|
||||
bool m_autojoin;
|
||||
|
||||
public:
|
||||
thread_t(const std::string& name, bool autojoin, std::function<void()> func);
|
||||
thread_t(const std::string& name, std::function<void()> func);
|
||||
thread_t(const std::string& name);
|
||||
thread_t();
|
||||
@ -162,6 +164,9 @@ public:
|
||||
void notify(u64 signal_id);
|
||||
};
|
||||
|
||||
extern const std::function<bool()> SQUEUE_ALWAYS_EXIT;
|
||||
extern const std::function<bool()> SQUEUE_NEVER_EXIT;
|
||||
|
||||
bool squeue_test_exit();
|
||||
|
||||
template<typename T, u32 sq_size = 256>
|
||||
@ -266,14 +271,14 @@ public:
|
||||
return push(data, [do_exit](){ return do_exit && *do_exit; });
|
||||
}
|
||||
|
||||
bool push(const T& data)
|
||||
__forceinline bool push(const T& data)
|
||||
{
|
||||
return push(data, [](){ return false; });
|
||||
return push(data, SQUEUE_NEVER_EXIT);
|
||||
}
|
||||
|
||||
bool try_push(const T& data)
|
||||
__forceinline bool try_push(const T& data)
|
||||
{
|
||||
return push(data, [](){ return true; });
|
||||
return push(data, SQUEUE_ALWAYS_EXIT);
|
||||
}
|
||||
|
||||
bool pop(T& data, const std::function<bool()>& test_exit)
|
||||
@ -334,14 +339,14 @@ public:
|
||||
return pop(data, [do_exit](){ return do_exit && *do_exit; });
|
||||
}
|
||||
|
||||
bool pop(T& data)
|
||||
__forceinline bool pop(T& data)
|
||||
{
|
||||
return pop(data, [](){ return false; });
|
||||
return pop(data, SQUEUE_NEVER_EXIT);
|
||||
}
|
||||
|
||||
bool try_pop(T& data)
|
||||
__forceinline bool try_pop(T& data)
|
||||
{
|
||||
return pop(data, [](){ return true; });
|
||||
return pop(data, SQUEUE_ALWAYS_EXIT);
|
||||
}
|
||||
|
||||
bool peek(T& data, u32 start_pos, const std::function<bool()>& test_exit)
|
||||
@ -362,7 +367,7 @@ public:
|
||||
{
|
||||
return SQSVR_LOCKED;
|
||||
}
|
||||
|
||||
|
||||
sync.pop_lock = 1;
|
||||
pos = sync.position + start_pos;
|
||||
return SQSVR_OK;
|
||||
@ -396,14 +401,14 @@ public:
|
||||
return peek(data, start_pos, [do_exit](){ return do_exit && *do_exit; });
|
||||
}
|
||||
|
||||
bool peek(T& data, u32 start_pos = 0)
|
||||
__forceinline bool peek(T& data, u32 start_pos = 0)
|
||||
{
|
||||
return peek(data, start_pos, [](){ return false; });
|
||||
return peek(data, start_pos, SQUEUE_NEVER_EXIT);
|
||||
}
|
||||
|
||||
bool try_peek(T& data, u32 start_pos = 0)
|
||||
__forceinline bool try_peek(T& data, u32 start_pos = 0)
|
||||
{
|
||||
return peek(data, start_pos, [](){ return true; });
|
||||
return peek(data, start_pos, SQUEUE_ALWAYS_EXIT);
|
||||
}
|
||||
|
||||
class squeue_data_t
|
||||
|
@ -117,3 +117,40 @@ void CallbackManager::Clear()
|
||||
m_cb_list.clear();
|
||||
m_async_list.clear();
|
||||
}
|
||||
|
||||
u64 CallbackManager::AddPauseCallback(const std::function<PauseResumeCB>& func)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
m_pause_cb_list.push_back({ func, next_tag });
|
||||
return next_tag++;
|
||||
}
|
||||
|
||||
void CallbackManager::RemovePauseCallback(const u64 tag)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
for (auto& data : m_pause_cb_list)
|
||||
{
|
||||
if (data.tag == tag)
|
||||
{
|
||||
m_pause_cb_list.erase(m_pause_cb_list.begin() + (&data - m_pause_cb_list.data()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
assert(!"CallbackManager()::RemovePauseCallback(): tag not found");
|
||||
}
|
||||
|
||||
void CallbackManager::RunPauseCallbacks(const bool is_paused)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
for (auto& data : m_pause_cb_list)
|
||||
{
|
||||
if (data.cb)
|
||||
{
|
||||
data.cb(is_paused);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,21 +3,62 @@
|
||||
class CPUThread;
|
||||
class PPUThread;
|
||||
|
||||
typedef void(PauseResumeCB)(bool is_paused);
|
||||
|
||||
class CallbackManager
|
||||
{
|
||||
std::vector<std::function<s32(CPUThread& CPU)>> m_cb_list;
|
||||
std::vector<std::function<void(CPUThread& CPU)>> m_async_list;
|
||||
CPUThread* m_cb_thread;
|
||||
std::mutex m_mutex;
|
||||
std::vector<std::function<s32(CPUThread&)>> m_cb_list;
|
||||
std::vector<std::function<void(CPUThread&)>> m_async_list;
|
||||
CPUThread* m_cb_thread;
|
||||
|
||||
struct PauseResumeCBS
|
||||
{
|
||||
std::function<PauseResumeCB> cb;
|
||||
u64 tag;
|
||||
};
|
||||
|
||||
u64 next_tag; // not initialized, only increased
|
||||
std::vector<PauseResumeCBS> m_pause_cb_list;
|
||||
|
||||
public:
|
||||
void Register(const std::function<s32(PPUThread& PPU)>& func); // register callback (called in Check() method)
|
||||
void Register(const std::function<s32(PPUThread& CPU)>& func); // register callback (called in Check() method)
|
||||
|
||||
void Async(const std::function<void(PPUThread& PPU)>& func); // register callback for callback thread (called immediately)
|
||||
void Async(const std::function<void(PPUThread& CPU)>& func); // register callback for callback thread (called immediately)
|
||||
|
||||
bool Check(CPUThread& CPU, s32& result); // call one callback registered by Register() method
|
||||
|
||||
void Init();
|
||||
|
||||
void Clear();
|
||||
|
||||
u64 AddPauseCallback(const std::function<PauseResumeCB>& func); // register callback for pausing/resuming emulation events
|
||||
void RemovePauseCallback(const u64 tag); // unregister callback (uses the result of AddPauseCallback() function)
|
||||
void RunPauseCallbacks(const bool is_paused);
|
||||
};
|
||||
|
||||
class PauseCallbackRegisterer
|
||||
{
|
||||
CallbackManager& cb_manager;
|
||||
u64 cb_tag;
|
||||
|
||||
public:
|
||||
PauseCallbackRegisterer(CallbackManager& cb_manager, const std::function<PauseResumeCB>& func)
|
||||
: cb_manager(cb_manager)
|
||||
, cb_tag(cb_manager.AddPauseCallback(func))
|
||||
{
|
||||
}
|
||||
|
||||
PauseCallbackRegisterer() = delete;
|
||||
PauseCallbackRegisterer(const PauseCallbackRegisterer& right) = delete;
|
||||
PauseCallbackRegisterer(PauseCallbackRegisterer&& right) = delete;
|
||||
|
||||
~PauseCallbackRegisterer()
|
||||
{
|
||||
cb_manager.RemovePauseCallback(cb_tag);
|
||||
}
|
||||
|
||||
PauseCallbackRegisterer& operator =(const PauseCallbackRegisterer& right) = delete;
|
||||
PauseCallbackRegisterer& operator =(PauseCallbackRegisterer&& right) = delete;
|
||||
|
||||
};
|
||||
|
@ -18,7 +18,7 @@ Module *cellAudio = nullptr;
|
||||
|
||||
AudioConfig g_audio;
|
||||
|
||||
int cellAudioInit()
|
||||
s32 cellAudioInit()
|
||||
{
|
||||
cellAudio->Warning("cellAudioInit()");
|
||||
|
||||
@ -27,23 +27,27 @@ int cellAudioInit()
|
||||
return CELL_AUDIO_ERROR_ALREADY_INIT;
|
||||
}
|
||||
|
||||
// clear ports
|
||||
for (auto& port : g_audio.ports)
|
||||
{
|
||||
port.state.write_relaxed(AUDIO_PORT_STATE_NOT_OPENED);
|
||||
port.state.write_relaxed(AUDIO_PORT_STATE_CLOSED);
|
||||
}
|
||||
|
||||
// reset variables
|
||||
g_audio.start_time = 0;
|
||||
g_audio.counter = 0;
|
||||
g_audio.keys.clear();
|
||||
g_audio.start_time = get_system_time();
|
||||
|
||||
// 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.buffer = g_audio.buffer ? g_audio.buffer : vm::cast(Memory.MainMem.AllocAlign(AUDIO_PORT_OFFSET * 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<void>(g_audio.buffer), 0, 128 * 1024 * AUDIO_PORT_COUNT);
|
||||
memset(vm::get_ptr<void>(g_audio.buffer), 0, AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT);
|
||||
memset(vm::get_ptr<void>(g_audio.indexes), 0, sizeof(u64) * AUDIO_PORT_COUNT);
|
||||
|
||||
// start audio thread
|
||||
g_audio.audio_thread.start([]()
|
||||
{
|
||||
const bool do_dump = Ini.AudioDumpToFile.GetValue();
|
||||
@ -51,8 +55,7 @@ int cellAudioInit()
|
||||
AudioDumper m_dump;
|
||||
if (do_dump && !m_dump.Init(8)) // Init AudioDumper for 8 channels
|
||||
{
|
||||
cellAudio->Error("AudioDumper::Init() failed");
|
||||
return;
|
||||
throw "AudioDumper::Init() failed";
|
||||
}
|
||||
|
||||
float buf2ch[2 * BUFFER_SIZE]; // intermediate buffer for 2 channels
|
||||
@ -67,69 +70,60 @@ int cellAudioInit()
|
||||
out_buffer[i].reset(new float[2 * BUFFER_SIZE] {});
|
||||
}
|
||||
|
||||
squeue_t<float*, 31> out_queue;
|
||||
squeue_t<float*, BUFFER_NUM - 1> out_queue;
|
||||
|
||||
std::vector<u64> keys;
|
||||
|
||||
g_audio.start_time = get_system_time();
|
||||
|
||||
thread_t iat("Internal Audio Thread", [&out_queue]()
|
||||
thread_t iat("Internal Audio Thread", true /* autojoin */, [&out_queue]()
|
||||
{
|
||||
const bool use_u16 = Ini.AudioConvertToU16.GetValue();
|
||||
|
||||
Emu.GetAudioManager().GetAudioOut().Init();
|
||||
|
||||
bool opened = false;
|
||||
float* buffer;
|
||||
|
||||
while (g_audio.state.read_relaxed() == AUDIO_STATE_INITIALIZED && !Emu.IsStopped())
|
||||
while (out_queue.pop(buffer, [](){ return g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED; }))
|
||||
{
|
||||
float* buffer;
|
||||
if (out_queue.pop(buffer, [](){ return g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED; }))
|
||||
if (use_u16)
|
||||
{
|
||||
if (use_u16)
|
||||
// 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)
|
||||
|
||||
u16 buf_u16[out_buffer_size];
|
||||
for (size_t i = 0; i < out_buffer_size; i += 8)
|
||||
{
|
||||
// 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)
|
||||
static const __m128 float2u16 = { 0x8000, 0x8000, 0x8000, 0x8000 };
|
||||
(__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)));
|
||||
}
|
||||
|
||||
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&)(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)));
|
||||
}
|
||||
|
||||
if (!opened)
|
||||
{
|
||||
Emu.GetAudioManager().GetAudioOut().Open(buf_u16, out_buffer_size * sizeof(u16));
|
||||
opened = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Emu.GetAudioManager().GetAudioOut().AddData(buf_u16, out_buffer_size * sizeof(u16));
|
||||
}
|
||||
if (!opened)
|
||||
{
|
||||
Emu.GetAudioManager().GetAudioOut().Open(buf_u16, out_buffer_size * sizeof(u16));
|
||||
opened = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
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));
|
||||
}
|
||||
Emu.GetAudioManager().GetAudioOut().AddData(buf_u16, out_buffer_size * sizeof(u16));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,7 +137,7 @@ int cellAudioInit()
|
||||
// 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)
|
||||
if (g_audio.counter * AUDIO_SAMPLES * MHZ / 48000 >= stamp0 - g_audio.start_time)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
continue;
|
||||
@ -165,14 +159,39 @@ int cellAudioInit()
|
||||
{
|
||||
if (port.state.read_relaxed() != AUDIO_PORT_STATE_STARTED) continue;
|
||||
|
||||
const u32 block_size = port.channel * 256;
|
||||
const u32 block_size = port.channel * AUDIO_SAMPLES;
|
||||
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<be_t<float>>(buf_addr);
|
||||
|
||||
static const float k = 1.0f; // may be 1.0f
|
||||
const float m = port.level;
|
||||
const float& m = port.level;
|
||||
|
||||
auto step_volume = [](AudioPortConfig& port) // part of cellAudioSetPortLevel functionality
|
||||
{
|
||||
if (port.level_inc)
|
||||
{
|
||||
port.level += port.level_inc;
|
||||
|
||||
if (port.level_inc > 0.0f)
|
||||
{
|
||||
if (port.level_set - port.level <= 0.0f)
|
||||
{
|
||||
port.level = port.level_set;
|
||||
port.level_inc = 0.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (port.level_set - port.level >= 0.0f)
|
||||
{
|
||||
port.level = port.level_set;
|
||||
port.level_inc = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (port.channel == 2)
|
||||
{
|
||||
@ -180,6 +199,8 @@ int cellAudioInit()
|
||||
{
|
||||
for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2)
|
||||
{
|
||||
step_volume(port);
|
||||
|
||||
// reverse byte order
|
||||
const float left = buf[i + 0] * m;
|
||||
const float right = buf[i + 1] * m;
|
||||
@ -202,6 +223,8 @@ int cellAudioInit()
|
||||
{
|
||||
for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2)
|
||||
{
|
||||
step_volume(port);
|
||||
|
||||
const float left = buf[i + 0] * m;
|
||||
const float right = buf[i + 1] * m;
|
||||
|
||||
@ -213,64 +236,14 @@ int cellAudioInit()
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
step_volume(port);
|
||||
|
||||
const float left = buf[i * 4 + 0] * m;
|
||||
const float right = buf[i * 4 + 1] * m;
|
||||
const float center = buf[i * 4 + 2] * m;
|
||||
@ -299,6 +272,8 @@ int cellAudioInit()
|
||||
{
|
||||
for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2)
|
||||
{
|
||||
step_volume(port);
|
||||
|
||||
const float left = buf[i * 4 + 0] * m;
|
||||
const float right = buf[i * 4 + 1] * m;
|
||||
const float center = buf[i * 4 + 2] * m;
|
||||
@ -323,6 +298,10 @@ int cellAudioInit()
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw fmt::format("Unknown channel count (port=%d, channel=%d)", &port - g_audio.ports, port.channel);
|
||||
}
|
||||
|
||||
memset(buf, 0, block_size * sizeof(float));
|
||||
}
|
||||
@ -384,36 +363,31 @@ int cellAudioInit()
|
||||
{
|
||||
if (m_dump.WriteData(&buf8ch, sizeof(buf8ch)) != sizeof(buf8ch)) // write file data
|
||||
{
|
||||
cellAudio->Error("AudioDumper::WriteData() failed");
|
||||
break;
|
||||
throw "AudioDumper::WriteData() failed (2 ch)";
|
||||
}
|
||||
}
|
||||
else if (m_dump.GetCh() == 2)
|
||||
{
|
||||
if (m_dump.WriteData(&buf2ch, sizeof(buf2ch)) != sizeof(buf2ch)) // write file data
|
||||
{
|
||||
cellAudio->Error("AudioDumper::WriteData() failed");
|
||||
break;
|
||||
throw "AudioDumper::WriteData() failed (8 ch)";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cellAudio->Error("AudioDumper::GetCh() returned unknown value (%d)", m_dump.GetCh());
|
||||
break;
|
||||
throw fmt::format("AudioDumper::GetCh() returned unknown value (%d)", m_dump.GetCh());
|
||||
}
|
||||
}
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
iat.join();
|
||||
});
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellAudioQuit()
|
||||
s32 cellAudioQuit()
|
||||
{
|
||||
cellAudio->Warning("cellAudioQuit()");
|
||||
|
||||
@ -427,84 +401,153 @@ int cellAudioQuit()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellAudioPortOpen(vm::ptr<CellAudioPortParam> audioParam, vm::ptr<u32> portNum)
|
||||
s32 cellAudioPortOpen(vm::ptr<CellAudioPortParam> audioParam, vm::ptr<u32> portNum)
|
||||
{
|
||||
cellAudio->Warning("cellAudioPortOpen(audioParam_addr=0x%x, portNum_addr=0x%x)", audioParam.addr(), portNum.addr());
|
||||
cellAudio->Warning("cellAudioPortOpen(audioParam=0x%x, portNum=0x%x)", audioParam, portNum);
|
||||
|
||||
if (audioParam->nChannel > 8 || audioParam->nBlock > 16)
|
||||
if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
if (!audioParam || !portNum)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < AUDIO_PORT_COUNT; i++)
|
||||
const u64 channel = audioParam->nChannel;
|
||||
const u64 block = audioParam->nBlock;
|
||||
const u64 attr = audioParam->attr;
|
||||
|
||||
// check attributes
|
||||
if (channel != CELL_AUDIO_PORT_2CH &&
|
||||
channel != CELL_AUDIO_PORT_8CH &&
|
||||
channel)
|
||||
{
|
||||
if (g_audio.ports[i].state.compare_and_swap_test(AUDIO_PORT_STATE_NOT_OPENED, AUDIO_PORT_STATE_OPENED))
|
||||
{
|
||||
AudioPortConfig& port = g_audio.ports[i];
|
||||
|
||||
port.channel = (u8)audioParam->nChannel;
|
||||
port.block = (u8)audioParam->nBlock;
|
||||
port.attr = audioParam->attr;
|
||||
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)
|
||||
{
|
||||
port.level = audioParam->level;
|
||||
}
|
||||
else
|
||||
{
|
||||
port.level = 1.0f;
|
||||
}
|
||||
|
||||
*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.tag = 0;
|
||||
return CELL_OK;
|
||||
}
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
return CELL_AUDIO_ERROR_PORT_FULL;
|
||||
if (block != CELL_AUDIO_BLOCK_8 &&
|
||||
block != CELL_AUDIO_BLOCK_16 &&
|
||||
block != 2 &&
|
||||
block != 4 &&
|
||||
block != 32)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
// list unsupported flags
|
||||
if (attr & CELL_AUDIO_PORTATTR_BGM)
|
||||
{
|
||||
cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_BGM");
|
||||
}
|
||||
if (attr & CELL_AUDIO_PORTATTR_OUT_SECONDARY)
|
||||
{
|
||||
cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_SECONDARY");
|
||||
}
|
||||
if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_0)
|
||||
{
|
||||
cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_0");
|
||||
}
|
||||
if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_1)
|
||||
{
|
||||
cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_1");
|
||||
}
|
||||
if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_2)
|
||||
{
|
||||
cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_2");
|
||||
}
|
||||
if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_3)
|
||||
{
|
||||
cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_3");
|
||||
}
|
||||
if (attr & CELL_AUDIO_PORTATTR_OUT_NO_ROUTE)
|
||||
{
|
||||
cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_NO_ROUTE");
|
||||
}
|
||||
if (attr & 0xFFFFFFFFF0EFEFEEULL)
|
||||
{
|
||||
cellAudio->Todo("cellAudioPortOpen(): unknown attributes set (0x%llx)", attr);
|
||||
}
|
||||
|
||||
// open audio port
|
||||
const u32 port_index = g_audio.open_port();
|
||||
|
||||
if (!~port_index)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PORT_FULL;
|
||||
}
|
||||
|
||||
AudioPortConfig& port = g_audio.ports[port_index];
|
||||
|
||||
port.channel = (u32)channel;
|
||||
port.block = (u32)block;
|
||||
port.attr = attr;
|
||||
port.addr = g_audio.buffer + AUDIO_PORT_OFFSET * port_index;
|
||||
port.read_index_addr = g_audio.indexes + sizeof(u64) * port_index;
|
||||
port.size = port.channel * port.block * AUDIO_SAMPLES * sizeof(float);
|
||||
port.tag = 0;
|
||||
|
||||
if (port.attr & CELL_AUDIO_PORTATTR_INITLEVEL)
|
||||
{
|
||||
port.level = audioParam->level;
|
||||
}
|
||||
else
|
||||
{
|
||||
port.level = 1.0f;
|
||||
}
|
||||
|
||||
port.level_set = port.level;
|
||||
port.level_inc = 0.0f;
|
||||
|
||||
*portNum = port_index;
|
||||
cellAudio->Warning("*** audio port opened(nChannel=%d, nBlock=%d, attr=0x%llx, level=%f): port = %d", channel, block, attr, port.level, port_index);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellAudioGetPortConfig(u32 portNum, vm::ptr<CellAudioPortConfig> portConfig)
|
||||
s32 cellAudioGetPortConfig(u32 portNum, vm::ptr<CellAudioPortConfig> portConfig)
|
||||
{
|
||||
cellAudio->Warning("cellAudioGetPortConfig(portNum=0x%x, portConfig_addr=0x%x)", portNum, portConfig.addr());
|
||||
cellAudio->Warning("cellAudioGetPortConfig(portNum=0x%x, portConfig=0x%x)", portNum, portConfig);
|
||||
|
||||
if (portNum >= AUDIO_PORT_COUNT)
|
||||
if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
if (!portConfig || portNum >= AUDIO_PORT_COUNT)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
switch (auto state = g_audio.ports[portNum].state.read_sync())
|
||||
AudioPortConfig& port = g_audio.ports[portNum];
|
||||
|
||||
portConfig->readIndexAddr = port.read_index_addr;
|
||||
|
||||
switch (auto state = port.state.read_sync())
|
||||
{
|
||||
case AUDIO_PORT_STATE_NOT_OPENED: portConfig->status = CELL_AUDIO_STATUS_CLOSE; break;
|
||||
case AUDIO_PORT_STATE_CLOSED: 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 = g_audio.ports[portNum];
|
||||
|
||||
portConfig->nChannel = port.channel;
|
||||
portConfig->nBlock = port.block;
|
||||
portConfig->portSize = port.size;
|
||||
portConfig->portAddr = port.addr; // 0x20020000
|
||||
portConfig->readIndexAddr = port.read_index_addr; // 0x20010010 on ps3
|
||||
|
||||
cellAudio->Log("*** port config: nChannel=%d, nBlock=%d, portSize=0x%x, portAddr=0x%x, readIndexAddr=0x%x",
|
||||
(u32)portConfig->nChannel, (u32)portConfig->nBlock, (u32)portConfig->portSize, (u32)portConfig->portAddr, (u32)portConfig->readIndexAddr);
|
||||
// portAddr - readIndexAddr == 0xFFF0 on ps3
|
||||
|
||||
portConfig->portAddr = port.addr;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellAudioPortStart(u32 portNum)
|
||||
s32 cellAudioPortStart(u32 portNum)
|
||||
{
|
||||
cellAudio->Warning("cellAudioPortStart(portNum=0x%x)", portNum);
|
||||
|
||||
if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
if (portNum >= AUDIO_PORT_COUNT)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
@ -512,35 +555,45 @@ int cellAudioPortStart(u32 portNum)
|
||||
|
||||
switch (auto state = g_audio.ports[portNum].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED))
|
||||
{
|
||||
case AUDIO_PORT_STATE_NOT_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
|
||||
case AUDIO_PORT_STATE_CLOSED: 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);
|
||||
}
|
||||
}
|
||||
|
||||
int cellAudioPortClose(u32 portNum)
|
||||
s32 cellAudioPortClose(u32 portNum)
|
||||
{
|
||||
cellAudio->Warning("cellAudioPortClose(portNum=0x%x)", portNum);
|
||||
|
||||
if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
if (portNum >= AUDIO_PORT_COUNT)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
switch (auto state = g_audio.ports[portNum].state.exchange(AUDIO_PORT_STATE_NOT_OPENED))
|
||||
switch (auto state = g_audio.ports[portNum].state.exchange(AUDIO_PORT_STATE_CLOSED))
|
||||
{
|
||||
case AUDIO_PORT_STATE_NOT_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
|
||||
case AUDIO_PORT_STATE_CLOSED: 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);
|
||||
}
|
||||
}
|
||||
|
||||
int cellAudioPortStop(u32 portNum)
|
||||
s32 cellAudioPortStop(u32 portNum)
|
||||
{
|
||||
cellAudio->Warning("cellAudioPortStop(portNum=0x%x)", portNum);
|
||||
|
||||
if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
if (portNum >= AUDIO_PORT_COUNT)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
@ -548,34 +601,36 @@ int cellAudioPortStop(u32 portNum)
|
||||
|
||||
switch (auto state = g_audio.ports[portNum].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED))
|
||||
{
|
||||
case AUDIO_PORT_STATE_NOT_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
|
||||
case AUDIO_PORT_STATE_CLOSED: return CELL_AUDIO_ERROR_PORT_NOT_RUN;
|
||||
case AUDIO_PORT_STATE_STARTED: return CELL_OK;
|
||||
case AUDIO_PORT_STATE_OPENED: return CELL_AUDIO_ERROR_PORT_OPEN;
|
||||
case AUDIO_PORT_STATE_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_RUN;
|
||||
default: throw fmt::format("cellAudioPortStop(%d): invalid port state (0x%x)", portNum, state);
|
||||
}
|
||||
}
|
||||
|
||||
int cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr<u64> stamp)
|
||||
s32 cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr<u64> stamp)
|
||||
{
|
||||
cellAudio->Log("cellAudioGetPortTimestamp(portNum=0x%x, tag=0x%llx, stamp_addr=0x%x)", portNum, tag, stamp.addr());
|
||||
cellAudio->Log("cellAudioGetPortTimestamp(portNum=0x%x, tag=0x%llx, stamp=0x%x)", portNum, tag, stamp);
|
||||
|
||||
if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
if (portNum >= AUDIO_PORT_COUNT)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
//if (!g_audio.ports[portNum].is_audio_port_opened)
|
||||
//{
|
||||
// return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
|
||||
//}
|
||||
|
||||
//if (!g_audio.ports[portNum].is_audio_port_started)
|
||||
//{
|
||||
// return CELL_AUDIO_ERROR_PORT_NOT_RUN;
|
||||
//}
|
||||
|
||||
AudioPortConfig& port = g_audio.ports[portNum];
|
||||
|
||||
if (port.state.read_relaxed() == AUDIO_PORT_STATE_CLOSED)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
|
||||
}
|
||||
|
||||
// TODO: check tag (CELL_AUDIO_ERROR_TAG_NOT_FOUND error)
|
||||
|
||||
std::lock_guard<std::mutex> lock(g_audio.mutex);
|
||||
|
||||
*stamp = g_audio.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000;
|
||||
@ -583,30 +638,29 @@ int cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr<u64> stamp)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr<u64> tag)
|
||||
s32 cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr<u64> tag)
|
||||
{
|
||||
cellAudio->Log("cellAudioGetPortBlockTag(portNum=0x%x, blockNo=0x%llx, tag_addr=0x%x)", portNum, blockNo, tag.addr());
|
||||
cellAudio->Log("cellAudioGetPortBlockTag(portNum=0x%x, blockNo=0x%llx, tag=0x%x)", portNum, blockNo, tag);
|
||||
|
||||
if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
if (portNum >= AUDIO_PORT_COUNT)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
//if (!g_audio.ports[portNum].is_audio_port_opened)
|
||||
//{
|
||||
// return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
|
||||
//}
|
||||
|
||||
//if (!g_audio.ports[portNum].is_audio_port_started)
|
||||
//{
|
||||
// return CELL_AUDIO_ERROR_PORT_NOT_RUN;
|
||||
//}
|
||||
|
||||
AudioPortConfig& port = g_audio.ports[portNum];
|
||||
|
||||
if (port.state.read_relaxed() == AUDIO_PORT_STATE_CLOSED)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
|
||||
}
|
||||
|
||||
if (blockNo >= port.block)
|
||||
{
|
||||
cellAudio->Error("cellAudioGetPortBlockTag: wrong blockNo(%lld)", blockNo);
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
@ -627,9 +681,14 @@ int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr<u64> tag)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellAudioSetPortLevel(u32 portNum, float level)
|
||||
s32 cellAudioSetPortLevel(u32 portNum, float level)
|
||||
{
|
||||
cellAudio->Todo("cellAudioSetPortLevel(portNum=0x%x, level=%f)", portNum, level);
|
||||
cellAudio->Log("cellAudioSetPortLevel(portNum=0x%x, level=%f)", portNum, level);
|
||||
|
||||
if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
if (portNum >= AUDIO_PORT_COUNT)
|
||||
{
|
||||
@ -638,19 +697,22 @@ int cellAudioSetPortLevel(u32 portNum, float level)
|
||||
|
||||
AudioPortConfig& port = g_audio.ports[portNum];
|
||||
|
||||
//if (!port.is_audio_port_opened)
|
||||
//{
|
||||
// return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
|
||||
//}
|
||||
if (port.state.read_relaxed() == AUDIO_PORT_STATE_CLOSED)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
|
||||
}
|
||||
|
||||
//if (!port.is_audio_port_started)
|
||||
//{
|
||||
// return CELL_AUDIO_ERROR_PORT_NOT_RUN;
|
||||
//}
|
||||
if (level >= 0.0f)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_audio.mutex);
|
||||
|
||||
std::lock_guard<std::mutex> lock(g_audio.mutex);
|
||||
|
||||
port.level = level; // TODO
|
||||
port.level_set = level;
|
||||
port.level_inc = (port.level - level) / 624.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
cellAudio->Todo("cellAudioSetPortLevel(portNum=0x%x): negative level value (%f)", portNum, level);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -77,6 +77,8 @@ enum : u32
|
||||
BUFFER_NUM = 32,
|
||||
BUFFER_SIZE = 256,
|
||||
AUDIO_PORT_COUNT = 8,
|
||||
AUDIO_PORT_OFFSET = 256 * 1024,
|
||||
AUDIO_SAMPLES = CELL_AUDIO_BLOCK_SAMPLES,
|
||||
};
|
||||
|
||||
enum AudioState : u32
|
||||
@ -88,7 +90,7 @@ enum AudioState : u32
|
||||
|
||||
enum AudioPortState : u32
|
||||
{
|
||||
AUDIO_PORT_STATE_NOT_OPENED,
|
||||
AUDIO_PORT_STATE_CLOSED,
|
||||
AUDIO_PORT_STATE_OPENED,
|
||||
AUDIO_PORT_STATE_STARTED,
|
||||
};
|
||||
@ -98,15 +100,17 @@ struct AudioPortConfig
|
||||
std::mutex mutex;
|
||||
atomic_le_t<AudioPortState> state;
|
||||
|
||||
u8 channel;
|
||||
u8 block;
|
||||
float level;
|
||||
u32 channel;
|
||||
u32 block;
|
||||
u64 attr;
|
||||
u64 tag;
|
||||
u64 counter; // copy of global counter
|
||||
u32 addr;
|
||||
u32 read_index_addr;
|
||||
u32 size;
|
||||
float level;
|
||||
float level_set;
|
||||
float level_inc;
|
||||
};
|
||||
|
||||
struct AudioConfig //custom structure
|
||||
@ -125,6 +129,19 @@ struct AudioConfig //custom structure
|
||||
AudioConfig() : audio_thread("Audio Thread")
|
||||
{
|
||||
}
|
||||
|
||||
u32 open_port()
|
||||
{
|
||||
for (u32 i = 0; i < AUDIO_PORT_COUNT; i++)
|
||||
{
|
||||
if (ports[i].state.compare_and_swap_test(AUDIO_PORT_STATE_CLOSED, AUDIO_PORT_STATE_OPENED))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return ~0;
|
||||
}
|
||||
};
|
||||
|
||||
extern AudioConfig g_audio;
|
||||
|
@ -10,9 +10,7 @@
|
||||
|
||||
Module *libmixer = nullptr;
|
||||
|
||||
CellSurMixerConfig surMixer;
|
||||
|
||||
#define SUR_PORT (7)
|
||||
SurMixerConfig g_surmx;
|
||||
vm::ptr<CellSurMixerNotifyCallbackFunction> surMixerCb;
|
||||
vm::ptr<void> surMixerCbArg;
|
||||
std::mutex mixer_mutex;
|
||||
@ -31,13 +29,13 @@ int cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, vm::ptr<float> addr
|
||||
switch (type)
|
||||
{
|
||||
case CELL_SURMIXER_CHSTRIP_TYPE1A:
|
||||
if (port >= surMixer.chStrips1) type = 0; break;
|
||||
if (port >= g_surmx.ch_strips_1) type = 0; break;
|
||||
case CELL_SURMIXER_CHSTRIP_TYPE2A:
|
||||
if (port >= surMixer.chStrips2) type = 0; break;
|
||||
if (port >= g_surmx.ch_strips_2) type = 0; break;
|
||||
case CELL_SURMIXER_CHSTRIP_TYPE6A:
|
||||
if (port >= surMixer.chStrips6) type = 0; break;
|
||||
if (port >= g_surmx.ch_strips_6) type = 0; break;
|
||||
case CELL_SURMIXER_CHSTRIP_TYPE8A:
|
||||
if (port >= surMixer.chStrips8) type = 0; break;
|
||||
if (port >= g_surmx.ch_strips_8) type = 0; break;
|
||||
default:
|
||||
type = 0; break;
|
||||
}
|
||||
@ -296,15 +294,21 @@ int cellSurMixerCreate(vm::ptr<const CellSurMixerConfig> config)
|
||||
{
|
||||
libmixer->Warning("cellSurMixerCreate(config_addr=0x%x)", config.addr());
|
||||
|
||||
surMixer = *config;
|
||||
g_surmx.audio_port = g_audio.open_port();
|
||||
|
||||
AudioPortConfig& port = g_audio.ports[SUR_PORT];
|
||||
|
||||
if (!port.state.compare_and_swap_test(AUDIO_PORT_STATE_NOT_OPENED, AUDIO_PORT_STATE_OPENED))
|
||||
if (!~g_surmx.audio_port)
|
||||
{
|
||||
return CELL_LIBMIXER_ERROR_FULL;
|
||||
}
|
||||
|
||||
g_surmx.priority = config->priority;
|
||||
g_surmx.ch_strips_1 = config->chStrips1;
|
||||
g_surmx.ch_strips_2 = config->chStrips2;
|
||||
g_surmx.ch_strips_6 = config->chStrips6;
|
||||
g_surmx.ch_strips_8 = config->chStrips8;
|
||||
|
||||
AudioPortConfig& port = g_audio.ports[g_surmx.audio_port];
|
||||
|
||||
port.channel = 8;
|
||||
port.block = 16;
|
||||
port.attr = 0;
|
||||
@ -316,12 +320,11 @@ int cellSurMixerCreate(vm::ptr<const CellSurMixerConfig> config)
|
||||
mixcount = 0;
|
||||
surMixerCb.set(0);
|
||||
|
||||
libmixer->Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)",
|
||||
(u32)surMixer.chStrips1, (u32)surMixer.chStrips2, (u32)surMixer.chStrips6, (u32)surMixer.chStrips8);
|
||||
libmixer->Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", config->chStrips1, config->chStrips2, config->chStrips6, config->chStrips8);
|
||||
|
||||
thread_t t("Surmixer Thread", []()
|
||||
{
|
||||
AudioPortConfig& port = g_audio.ports[SUR_PORT];
|
||||
AudioPortConfig& port = g_audio.ports[g_surmx.audio_port];
|
||||
|
||||
PPUThread& cb_thread = *(PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU);
|
||||
cb_thread.SetName("Surmixer Callback Thread");
|
||||
@ -332,14 +335,8 @@ int cellSurMixerCreate(vm::ptr<const CellSurMixerConfig> config)
|
||||
cb_thread.InitRegs();
|
||||
cb_thread.DoRun();
|
||||
|
||||
while (port.state.read_relaxed() != AUDIO_PORT_STATE_NOT_OPENED)
|
||||
while (port.state.read_relaxed() != AUDIO_PORT_STATE_CLOSED && !Emu.IsStopped())
|
||||
{
|
||||
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)); // hack
|
||||
@ -437,7 +434,7 @@ int cellSurMixerCreate(vm::ptr<const CellSurMixerConfig> config)
|
||||
|
||||
//u64 stamp2 = get_system_time();
|
||||
|
||||
auto buf = vm::get_ptr<be_t<float>>(g_audio.buffer + (128 * 1024 * SUR_PORT) + (mixcount % port.block) * port.channel * 256 * sizeof(float));
|
||||
auto buf = vm::get_ptr<be_t<float>>(port.addr + (mixcount % port.block) * port.channel * AUDIO_SAMPLES * sizeof(float));
|
||||
|
||||
for (u32 i = 0; i < (sizeof(mixdata) / sizeof(float)); i++)
|
||||
{
|
||||
@ -511,7 +508,12 @@ int cellSurMixerStart()
|
||||
{
|
||||
libmixer->Warning("cellSurMixerStart()");
|
||||
|
||||
g_audio.ports[SUR_PORT].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED);
|
||||
if (g_surmx.audio_port >= AUDIO_PORT_COUNT)
|
||||
{
|
||||
return CELL_LIBMIXER_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -526,12 +528,17 @@ int cellSurMixerFinalize()
|
||||
{
|
||||
libmixer->Warning("cellSurMixerFinalize()");
|
||||
|
||||
g_audio.ports[SUR_PORT].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_NOT_OPENED);
|
||||
if (g_surmx.audio_port >= AUDIO_PORT_COUNT)
|
||||
{
|
||||
return CELL_LIBMIXER_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_CLOSED);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellSurMixerSurBusAddData(u32 busNo, u32 offset, u32 addr, u32 samples)
|
||||
int cellSurMixerSurBusAddData(u32 busNo, u32 offset, vm::ptr<float> addr, u32 samples)
|
||||
{
|
||||
if (busNo < 8 && samples == 256 && offset == 0)
|
||||
{
|
||||
@ -548,8 +555,7 @@ int cellSurMixerSurBusAddData(u32 busNo, u32 offset, u32 addr, u32 samples)
|
||||
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;
|
||||
mixdata[i * 8 + busNo] += addr[i];
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@ -565,7 +571,12 @@ int cellSurMixerPause(u32 type)
|
||||
{
|
||||
libmixer->Warning("cellSurMixerPause(type=%d)", type);
|
||||
|
||||
g_audio.ports[SUR_PORT].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED);
|
||||
if (g_surmx.audio_port >= AUDIO_PORT_COUNT)
|
||||
{
|
||||
return CELL_LIBMIXER_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -617,6 +628,8 @@ void libmixer_init(Module *pxThis)
|
||||
{
|
||||
libmixer = pxThis;
|
||||
|
||||
g_surmx.audio_port = ~0;
|
||||
|
||||
REG_SUB(libmixer, "surmxAAN", cellAANAddData,
|
||||
0xffffffff7c691b78,
|
||||
0xffffffff7c0802a6,
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
enum //libmixer Error Codes
|
||||
// Error Codes
|
||||
enum
|
||||
{
|
||||
CELL_LIBMIXER_ERROR_NOT_INITIALIZED = 0x80310002,
|
||||
CELL_LIBMIXER_ERROR_INVALID_PARAMATER = 0x80310003,
|
||||
@ -164,6 +165,16 @@ struct CellSurMixerChStripParam
|
||||
be_t<s32> intVal;
|
||||
};
|
||||
|
||||
struct SurMixerConfig
|
||||
{
|
||||
u32 audio_port;
|
||||
s32 priority;
|
||||
u32 ch_strips_1;
|
||||
u32 ch_strips_2;
|
||||
u32 ch_strips_6;
|
||||
u32 ch_strips_8;
|
||||
};
|
||||
|
||||
struct SSPlayer
|
||||
{
|
||||
bool m_created; // SSPlayerCreate/Remove
|
||||
|
@ -1,6 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#define MHZ (1000000)
|
||||
enum : u32
|
||||
{
|
||||
MHZ = 1000000,
|
||||
};
|
||||
|
||||
// Auxiliary functions
|
||||
u64 get_time();
|
||||
|
@ -328,6 +328,8 @@ void Emulator::Pause()
|
||||
if (InterlockedCompareExchange((volatile u32*)&m_status, Paused, Running) == Running)
|
||||
{
|
||||
SendDbgCommand(DID_PAUSED_EMU);
|
||||
|
||||
GetCallbackManager().RunPauseCallbacks(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,6 +343,8 @@ void Emulator::Resume()
|
||||
CheckStatus();
|
||||
|
||||
SendDbgCommand(DID_RESUMED_EMU);
|
||||
|
||||
GetCallbackManager().RunPauseCallbacks(false);
|
||||
}
|
||||
|
||||
void Emulator::Stop()
|
||||
|
Loading…
Reference in New Issue
Block a user