Merge pull request #145 from Nekotekina/master

Fixed conflicts.
This commit is contained in:
Alexandro Sánchez Bach 2014-03-31 12:04:34 +02:00
parent 8011cc8ec4
commit 01dbb8eb9a
42 changed files with 1687 additions and 613 deletions

View file

@ -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++)