mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-11 01:08:39 +12:00
parent
8011cc8ec4
commit
01dbb8eb9a
42 changed files with 1687 additions and 613 deletions
|
@ -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
|
||||
|
@ -34,8 +38,10 @@ int cellAudioInit()
|
|||
thread t("Audio Thread", []()
|
||||
{
|
||||
AudioDumper m_dump(2); // WAV file header (stereo)
|
||||
|
||||
bool do_dump = Ini.AudioDumpToFile.GetValue();
|
||||
|
||||
if (Ini.AudioDumpToFile.GetValue() && !m_dump.Init())
|
||||
if (do_dump && !m_dump.Init())
|
||||
{
|
||||
ConLog.Error("Audio aborted: cannot create file!");
|
||||
return;
|
||||
|
@ -43,31 +49,54 @@ 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<float> buffer2[8*256]; // buffer for 8 channels (max count)
|
||||
//u16 oal_buffer[2*256]; // buffer for OpenAL
|
||||
float buffer[2*256]; // intermediate buffer for 2 channels
|
||||
|
||||
uint oal_buffer_offset = 0;
|
||||
uint oal_buffer_size = 2 * 256;
|
||||
std::unique_ptr<u16[]> 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));
|
||||
uint oal_buffer_size = sizeof(buffer) / sizeof(float);
|
||||
std::unique_ptr<u16[]> oal_buffer[32];
|
||||
SQueue<u16*, sizeof(oal_buffer) / sizeof(oal_buffer[0])> queue;
|
||||
for (u32 i = 0; i < queue.GetSize(); i++)
|
||||
{
|
||||
oal_buffer[i] = std::unique_ptr<u16[]>(new u16[oal_buffer_size]);
|
||||
memset(oal_buffer[i].get(), 0, oal_buffer_size * sizeof(u16));
|
||||
}
|
||||
queue.Clear();
|
||||
|
||||
Array<u64> 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();
|
||||
|
||||
volatile bool internal_finished = false;
|
||||
|
||||
thread iat("Internal Audio Thread", [oal_buffer_size, &queue, &internal_finished]()
|
||||
{
|
||||
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
|
||||
{
|
||||
internal_finished = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
iat.detach();
|
||||
|
||||
while (m_config.m_is_audio_initialized)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
|
@ -76,10 +105,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 +118,8 @@ int cellAudioInit()
|
|||
|
||||
m_config.counter++;
|
||||
|
||||
const u32 oal_pos = m_config.counter % queue.GetSize();
|
||||
|
||||
if (Emu.IsPaused())
|
||||
{
|
||||
continue;
|
||||
|
@ -94,68 +127,134 @@ int cellAudioInit()
|
|||
|
||||
bool first_mix = true;
|
||||
|
||||
// MIX:
|
||||
// mixing:
|
||||
for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++)
|
||||
{
|
||||
if (!m_config.m_ports[i].m_is_audio_port_started) continue;
|
||||
|
||||
AudioPortConfig& port = m_config.m_ports[i];
|
||||
mem64_t index(m_config.m_indexes + i * sizeof(u64));
|
||||
|
||||
const u32 block_size = port.channel * 256;
|
||||
const u32 position = port.tag % port.block; // old value
|
||||
const u32 buf_addr = m_config.m_buffer + (i * 128 * 1024) + (position * block_size * sizeof(float));
|
||||
|
||||
u32 position = port.tag % port.block; // old value
|
||||
auto buf = (be_t<float>*)&Memory[buf_addr];
|
||||
|
||||
u32 buf_addr = m_config.m_buffer + (i * 128 * 1024) + (position * block_size * sizeof(float));
|
||||
|
||||
memcpy(buffer2, Memory + buf_addr, block_size * sizeof(float));
|
||||
memset(Memory + buf_addr, 0, block_size * sizeof(float));
|
||||
static const float k = 1.0f;
|
||||
const float m = (port.level == 0.0f) ? 1.0f : port.level;
|
||||
|
||||
if (port.channel == 2)
|
||||
{
|
||||
SMutexGeneralLocker lock(port.m_mutex);
|
||||
if (first_mix)
|
||||
{
|
||||
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i++)
|
||||
{
|
||||
// reverse byte order
|
||||
buffer[i] = buf[i] * m;
|
||||
}
|
||||
first_mix = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i++)
|
||||
{
|
||||
buffer[i] += buf[i] * m;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (port.channel == 6)
|
||||
{
|
||||
if (first_mix)
|
||||
{
|
||||
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i += 2)
|
||||
{
|
||||
const float center = (buf[i*3+2] + buf[i*3+3]) * 0.708f;
|
||||
buffer[i] = (buf[i*3] + buf[i*3+4] + center) * k * m;
|
||||
buffer[i+1] = (buf[i*3+1] + buf[i*3+5] + center) * k * m;
|
||||
}
|
||||
first_mix = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i += 2)
|
||||
{
|
||||
const float center = (buf[i*3+2] + buf[i*3+3]) * 0.708f;
|
||||
buffer[i] += (buf[i*3] + buf[i*3+4] + center) * k * m;
|
||||
buffer[i+1] += (buf[i*3+1] + buf[i*3+5] + center) * k * m;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (port.channel == 8)
|
||||
{
|
||||
if (first_mix)
|
||||
{
|
||||
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i += 2)
|
||||
{
|
||||
const float center = (buf[i*4+2] + buf[i*4+3]) * 0.708f;
|
||||
buffer[i] = (buf[i*4] + buf[i*4+4] + buf[i*4+6] + center) * k * m;
|
||||
buffer[i+1] = (buf[i*4+1] + buf[i*4+5] + buf[i*4+7] + center) * k * m;
|
||||
}
|
||||
first_mix = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i += 2)
|
||||
{
|
||||
const float center = (buf[i*4+2] + buf[i*4+3]) * 0.708f;
|
||||
buffer[i] += (buf[i*4] + buf[i*4+4] + buf[i*4+6] + center) * k * m;
|
||||
buffer[i+1] += (buf[i*4+1] + buf[i*4+5] + buf[i*4+7] + center) * k * m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(buf, 0, block_size * sizeof(float));
|
||||
}
|
||||
|
||||
// convert the data from float to u16 and clip:
|
||||
if (!first_mix)
|
||||
{
|
||||
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i++)
|
||||
{
|
||||
oal_buffer[oal_pos][oal_buffer_offset + i] = (s16)(min<float>(max<float>(buffer[i] * 0x8000, -0x8000), 0x7fff));
|
||||
}
|
||||
}
|
||||
|
||||
const u64 stamp1 = get_system_time();
|
||||
|
||||
if (!first_mix)
|
||||
{
|
||||
oal_buffer_offset += sizeof(buffer) / sizeof(float);
|
||||
|
||||
if(oal_buffer_offset >= oal_buffer_size)
|
||||
{
|
||||
if(m_audio_out)
|
||||
{
|
||||
queue.Push(&oal_buffer[oal_pos][0]);
|
||||
}
|
||||
|
||||
oal_buffer_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const u64 stamp2 = get_system_time();
|
||||
|
||||
// send aftermix event (normal audio event)
|
||||
{
|
||||
SMutexGeneralLocker lock(audioMutex);
|
||||
// update indexes:
|
||||
for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++)
|
||||
{
|
||||
if (!m_config.m_ports[i].m_is_audio_port_started) continue;
|
||||
|
||||
AudioPortConfig& port = m_config.m_ports[i];
|
||||
mem64_t index(m_config.m_indexes + i * sizeof(u64));
|
||||
|
||||
u32 position = port.tag % port.block; // old value
|
||||
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;
|
||||
|
||||
if (first_mix)
|
||||
{
|
||||
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i += 2)
|
||||
{
|
||||
// reverse byte order (TODO: use port.m_param.level)
|
||||
buffer[i] = buffer2[i*k];
|
||||
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));
|
||||
}
|
||||
|
||||
first_mix = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i += 2)
|
||||
{
|
||||
buffer[i] = (buffer[i] + buffer2[i*k]) * 0.5; // TODO: valid mixing
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// send aftermix event (normal audio event)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_config.m_mutex);
|
||||
// load keys:
|
||||
keys.SetCount(m_config.m_keys.GetCount());
|
||||
memcpy(keys.GetPtr(), m_config.m_keys.GetPtr(), sizeof(u64) * keys.GetCount());
|
||||
}
|
||||
|
@ -165,19 +264,9 @@ int cellAudioInit()
|
|||
Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0);
|
||||
}
|
||||
|
||||
oal_buffer_offset += sizeof(buffer) / sizeof(float);
|
||||
const u64 stamp3 = get_system_time();
|
||||
|
||||
if(oal_buffer_offset >= oal_buffer_size)
|
||||
{
|
||||
if(m_audio_out)
|
||||
{
|
||||
m_audio_out->AddData(oal_buffer.get(), oal_buffer_offset * sizeof(u16));
|
||||
}
|
||||
|
||||
oal_buffer_offset = 0;
|
||||
}
|
||||
|
||||
if(Ini.AudioDumpToFile.GetValue())
|
||||
if (do_dump && !first_mix)
|
||||
{
|
||||
if (m_dump.WriteData(&buffer, sizeof(buffer)) != sizeof(buffer)) // write file data
|
||||
{
|
||||
|
@ -185,16 +274,49 @@ int cellAudioInit()
|
|||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
const u64 stamp4 = get_system_time();
|
||||
|
||||
//ConLog.Write("Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)",
|
||||
//stamp0 - m_config.start_time, stamp1-stamp0, stamp2-stamp1, stamp3-stamp2, stamp4-stamp3);
|
||||
}
|
||||
ConLog.Write("Audio finished");
|
||||
abort:
|
||||
if(Ini.AudioDumpToFile.GetValue())
|
||||
queue.Push(nullptr);
|
||||
|
||||
if(do_dump)
|
||||
m_dump.Finalize();
|
||||
|
||||
m_config.m_is_audio_initialized = false;
|
||||
|
||||
m_config.m_keys.Clear();
|
||||
for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++)
|
||||
{
|
||||
AudioPortConfig& port = m_config.m_ports[i];
|
||||
port.m_is_audio_port_opened = false;
|
||||
port.m_is_audio_port_started = false;
|
||||
}
|
||||
m_config.m_port_in_use = 0;
|
||||
|
||||
while (!internal_finished)
|
||||
{
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
m_config.m_is_audio_finalized = true;
|
||||
});
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -347,6 +469,7 @@ int cellAudioPortClose(u32 portNum)
|
|||
}
|
||||
|
||||
m_config.m_ports[portNum].m_is_audio_port_started = false;
|
||||
m_config.m_ports[portNum].m_is_audio_port_opened = false;
|
||||
m_config.m_port_in_use--;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -395,7 +518,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 +552,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 +580,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<std::mutex> lock(m_config.m_mutex);
|
||||
SMutexGeneralLocker lock(audioMutex);
|
||||
|
||||
u64 event_key = 0;
|
||||
while (Emu.GetEventManager().CheckKey((event_key << 48) | 0x80004d494f323221))
|
||||
|
@ -475,7 +598,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 +614,15 @@ int cellAudioSetNotifyEventQueue(u64 key)
|
|||
{
|
||||
cellAudio.Warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key);
|
||||
|
||||
std::lock_guard<std::mutex> 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 +646,7 @@ int cellAudioRemoveNotifyEventQueue(u64 key)
|
|||
{
|
||||
cellAudio.Warning("cellAudioRemoveNotifyEventQueue(key=0x%llx)", key);
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_config.m_mutex);
|
||||
SMutexGeneralLocker lock(audioMutex);
|
||||
|
||||
bool found = false;
|
||||
for (u32 i = 0; i < m_config.m_keys.GetCount(); i++)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue