Audio mixing fixed

Libmixer reseen
Some bugs fixed
This commit is contained in:
Nekotekina 2014-03-30 15:59:55 +04:00
parent 72bb0c842f
commit fce074d812
9 changed files with 178 additions and 82 deletions

1
.gitignore vendored
View File

@ -57,5 +57,4 @@ rpcs3/git-version.h
!/bin/dev_hdd0/game/TEST12345/
# Ignore other system generated files
bin/dev_hdd0/home/00000001/trophy
bin/dev_hdd0/log.txt

View File

@ -170,7 +170,8 @@ public:
}
break;
default: ConLog.Error("Init tex error: Bad tex format (0x%x | %s | 0x%x)", format, is_swizzled ? "swizzled" : "linear", tex.GetFormat() & 0x40); break;
default: ConLog.Error("Init tex error: Bad tex format (0x%x | %s | 0x%x)", format,
wxString(is_swizzled ? "swizzled" : "linear").wx_str(), tex.GetFormat() & 0x40); break;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, tex.GetMipmap() - 1);

View File

@ -949,7 +949,17 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t& args, const u3
case NV4097_SET_VIEWPORT_OFFSET:
{
/*const u32 offset0 = ARGS(0);
const u32 offset1 = ARGS(1);
const u32 offset2 = ARGS(2);
const u32 offset3 = ARGS(3);
const u32 scale0 = ARGS(4);
const u32 scale1 = ARGS(5);
const u32 scale2 = ARGS(6);
const u32 scale3 = ARGS(7);*/
//TODO
//ConLog.Warning("NV4097_SET_VIEWPORT_OFFSET: offset (%d, %d, %d, %d), scale (%d, %d, %d, %d)",
//offset0, offset1, offset2, offset3, scale0, scale1, scale2, scale3);
}
break;

View File

@ -38,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;
@ -50,7 +52,7 @@ int cellAudioInit()
if (Ini.AudioDumpToFile.GetValue())
m_dump.WriteHeader();
float buffer[2*256]; // buffer for 2 channels
float buffer[2*256]; // intermediate buffer for 2 channels
be_t<float> buffer2[8*256]; // buffer for 8 channels (max count)
//u16 oal_buffer[2*256]; // buffer for OpenAL
memset(buffer, 0, sizeof(buffer));
@ -79,7 +81,9 @@ int cellAudioInit()
m_config.start_time = get_system_time();
thread iat("Internal Audio Thread", [oal_buffer_size, &queue]()
volatile bool internal_finished = false;
thread iat("Internal Audio Thread", [oal_buffer_size, &queue, &internal_finished]()
{
while (true)
{
@ -92,7 +96,8 @@ int cellAudioInit()
}
else
{
break;
internal_finished = true;
return;
}
}
});
@ -128,13 +133,12 @@ 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;
@ -145,28 +149,17 @@ int cellAudioInit()
memcpy(buffer2, Memory + buf_addr, block_size * sizeof(float));
memset(Memory + buf_addr, 0, block_size * sizeof(float));
{
SMutexGeneralLocker lock(audioMutex);
port.counter = m_config.counter;
port.tag++; // absolute index of block that will be read
index = (position + 1) % port.block; // write new value
}
const 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)
// reverse byte order
buffer[i] = buffer2[i*k];
buffer[i+1] = buffer2[i*k+1];
// convert the data from float to u16
//assert(buffer[i] >= -1.0f && buffer[i] <= 1.0f);
//assert(buffer[i+1] >= -1.0f && buffer[i+1] <= 1.0f);
oal_buffer[oal_pos][oal_buffer_offset + i] = (u16)(buffer[i] * ((1 << 14) - 1));
oal_buffer[oal_pos][oal_buffer_offset + i + 1] = (u16)(buffer[i+1] * ((1 << 14) - 1));
// TODO: use port.m_param.level
// TODO: downmix channels that are ignored (?) or implement surround sound
}
first_mix = false;
@ -175,34 +168,20 @@ int cellAudioInit()
{
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] >= -1.0f && buffer[i] <= 1.0f);
//assert(buffer[i+1] >= -1.0f && buffer[i+1] <= 1.0f);
oal_buffer[oal_pos][oal_buffer_offset + i] = (u16)(buffer[i] * ((1 << 14) - 1));
oal_buffer[oal_pos][oal_buffer_offset + i + 1] = (u16)(buffer[i+1] * ((1 << 14) - 1));
buffer[i] += buffer2[i*k];
buffer[i+1] += buffer2[i*k+1];
}
}
}
// convert the data from float to u16 and clip:
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();
// send aftermix event (normal audio event)
{
SMutexGeneralLocker lock(audioMutex);
keys.SetCount(m_config.m_keys.GetCount());
memcpy(keys.GetPtr(), m_config.m_keys.GetPtr(), sizeof(u64) * keys.GetCount());
}
for (u32 i = 0; i < keys.GetCount(); i++)
{
// TODO: check event source
Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0);
}
const u64 stamp2 = get_system_time();
oal_buffer_offset += sizeof(buffer) / sizeof(float);
if(oal_buffer_offset >= oal_buffer_size)
@ -215,9 +194,37 @@ int cellAudioInit()
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
}
// load keys:
keys.SetCount(m_config.m_keys.GetCount());
memcpy(keys.GetPtr(), m_config.m_keys.GetPtr(), sizeof(u64) * keys.GetCount());
}
for (u32 i = 0; i < keys.GetCount(); i++)
{
// TODO: check event source
Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0);
}
const u64 stamp3 = get_system_time();
if(Ini.AudioDumpToFile.GetValue())
if(do_dump)
{
if (m_dump.WriteData(&buffer, sizeof(buffer)) != sizeof(buffer)) // write file data
{
@ -228,21 +235,24 @@ int cellAudioInit()
const u64 stamp4 = get_system_time();
//ConLog.Write("Audio perf: start=%d (access=%d, event=%d, AddData=%d, dump=%d)",
//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:
queue.Push(nullptr);
while (queue.GetCount())
if(do_dump)
m_dump.Finalize();
m_config.m_is_audio_initialized = false;
while (!internal_finished)
{
Sleep(1);
}
if(Ini.AudioDumpToFile.GetValue())
m_dump.Finalize();
m_config.m_is_audio_finalized = true;
m_config.m_is_audio_initialized = false;
});
t.detach();

View File

@ -12,13 +12,30 @@ CellSurMixerConfig surMixer;
#define SUR_PORT (7)
u32 surMixerCb = 0;
u32 surMixerCbArg = 0;
u64 mixcount = 0, stamp1 = 0, stamp2 = 0;
SMutex mixer_mutex;
bool mixfirst;
float mixdata[2*256];
u64 mixcount = 0;
int cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, u32 addr, u32 samples)
{
stamp1 = get_system_time();
u32 ch = aan_port >> 16;
u32 port = aan_port & 0xffff;
switch (ch)
{
case 1:
if (port >= surMixer.chStrips1) ch = 0; break;
case 2:
if (port >= surMixer.chStrips2) ch = 0; break;
case 6:
if (port >= surMixer.chStrips6) ch = 0; break;
case 8:
if (port >= surMixer.chStrips8) ch = 0; break;
default:
ch = 0;
}
if (aan_handle == 0x11111111 && aan_port == (2 << 16))
if (aan_handle == 0x11111111 && samples == 256 && ch && offset == 0)
{
libmixer.Log("cellAANAddData(handle=0x%x, port=0x%x, offset=0x%x, addr=0x%x, samples=0x%x)",
aan_handle, aan_port, offset, addr, samples);
@ -31,16 +48,28 @@ int cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, u32 addr, u32 sampl
return CELL_OK;
}
AudioPortConfig& port = m_config.m_ports[SUR_PORT];
SMutexLocker lock(mixer_mutex);
u32 to = m_config.m_buffer + (128 * 1024 * SUR_PORT) + ((mixcount + 12) % 16) * 2 * 256 * sizeof(float) + offset;
const u32 k = ch / 2;
if (!Memory.Copy(to, addr, 2 * samples * sizeof(float)))
if (mixfirst)
{
return CELL_LIBMIXER_ERROR_NO_MEMORY;
for (u32 i = 0; i < (sizeof(mixdata) / sizeof(float)); i += 2)
{
// reverse byte order and mix
mixdata[i] = *(be_t<float>*)&Memory[addr + i * k * sizeof(float)];
mixdata[i + 1] = *(be_t<float>*)&Memory[addr + (i * k + 1) * sizeof(float)];
}
mixfirst = false;
}
else
{
for (u32 i = 0; i < (sizeof(mixdata) / sizeof(float)); i += 2)
{
mixdata[i] += *(be_t<float>*)&Memory[addr + i * k * sizeof(float)];
mixdata[i + 1] += *(be_t<float>*)&Memory[addr + (i * k + 1) * sizeof(float)];
}
}
stamp2 = get_system_time();
return CELL_OK;
}
@ -119,14 +148,14 @@ int cellSurMixerGetAANHandle(mem32_t handle)
int cellSurMixerChStripGetAANPortNo(mem32_t port, u32 type, u32 index)
{
libmixer.Warning("cellSurMixerChStripGetAANPortNo(port_addr=0x%x, type=0x%x, index=0x%x) -> 0", port.GetAddr(), type, index);
libmixer.Warning("cellSurMixerChStripGetAANPortNo(port_addr=0x%x, type=0x%x, index=0x%x) -> 0x%x", port.GetAddr(), type, index, (type << 16) | index);
port = (type << 16) | index;
return CELL_OK;
}
int cellSurMixerSetNotifyCallback(u32 func, u32 arg)
{
libmixer.Warning("cellSurMixerSetNotifyCallback(func_addr=0x%x, arg=0x%x)", func, arg);
libmixer.Warning("cellSurMixerSetNotifyCallback(func_addr=0x%x, arg=0x%x) (surMixerCb=0x%x)", func, arg, surMixerCb);
surMixerCb = func;
surMixerCbArg = arg;
return CELL_OK;
@ -134,7 +163,7 @@ int cellSurMixerSetNotifyCallback(u32 func, u32 arg)
int cellSurMixerRemoveNotifyCallback(u32 func)
{
libmixer.Warning("cellSurMixerSetNotifyCallback(func_addr=0x%x)", func);
libmixer.Warning("cellSurMixerSetNotifyCallback(func_addr=0x%x) (surMixerCb=0x%x)", func, surMixerCb);
surMixerCb = 0;
surMixerCbArg = 0;
return CELL_OK;
@ -181,22 +210,38 @@ int cellSurMixerStart()
return;
}
if (mixcount > port.tag)
if (mixcount > (port.tag + 15)) // preemptive buffer filling (probably hack)
{
Sleep(1);
continue;
}
u64 stamp0 = get_system_time();
stamp1 = 0;
stamp2 = 0;
mixfirst = true;
mixerCb->ExecAsCallback(surMixerCb, true, surMixerCbArg, mixcount, 256);
u64 stamp3 = get_system_time();
u64 stamp1 = get_system_time();
//ConLog.Write("Libmixer perf: start=%d (cb_before=%d, cb=%d, cb_after=%d)",
//stamp0 - m_config.start_time, stamp1-stamp0, stamp2-stamp1, stamp3-stamp2);
auto buf = (be_t<float>*)&Memory[m_config.m_buffer + (128 * 1024 * SUR_PORT) + (mixcount % 16) * 2 * 256 * sizeof(float)];
if (!mixfirst)
{
for (u32 i = 0; i < (sizeof(mixdata) / sizeof(float)); i++)
{
// reverse byte order
buf[i] = mixdata[i];
}
}
else
{
// no data?
}
u64 stamp2 = get_system_time();
//ConLog.Write("Libmixer perf: start=%d (cb=%d, finalize=%d)",
//stamp0 - m_config.start_time, stamp1-stamp0, stamp2-stamp1);
mixcount++;
}
@ -229,7 +274,41 @@ int cellSurMixerFinalize()
int cellSurMixerSurBusAddData(u32 busNo, u32 offset, u32 addr, u32 samples)
{
libmixer.Error("cellSurMixerSurBusAddData(busNo=%d, offset=0x%x, addr=0x%x, samples=%d)", busNo, offset, addr, 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.Error("cellSurMixerSurBusAddData(busNo=%d, offset=0x%x, addr=0x%x, samples=%d)", busNo, offset, addr, samples);
Emu.Pause();
return CELL_OK;
}
if (busNo > 1) // channels from 3 to 8 ignored (TODO)
{
return CELL_OK;
}
SMutexLocker lock(mixer_mutex);
if (mixfirst)
{
for (u32 i = 0; i < samples; i++)
{
// reverse byte order and mix
mixdata[i * 2 + busNo] = *(be_t<float>*)&Memory[addr + i * sizeof(float)];
}
mixfirst = false;
}
else
{
for (u32 i = 0; i < samples; i++)
{
mixdata[i * 2 + busNo] += *(be_t<float>*)&Memory[addr + i * sizeof(float)];
}
}
return CELL_OK;
}

View File

@ -13,11 +13,7 @@ enum
CELL_LIBMIXER_ERROR_NOT_FOUND = 0x8031000a,
};
//Callback Functions
typedef int (*CellSurMixerNotifyCallbackFunction)(void *arg, u32 counter, u32 samples); //Currently unused.
//libmixer datatypes
typedef void * CellAANHandle;
typedef int (*CellSurMixerNotifyCallbackFunction)(void *arg, u32 counter, u32 samples);
struct CellSSPlayerConfig
{

View File

@ -28,7 +28,7 @@ int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_a
}
lwmutex->attribute = attr->attr_protocol | attr->attr_recursive;
lwmutex->all_info() = ~0;
lwmutex->waiter = 0;
lwmutex->mutex.initialize();
//lwmutex->waiter = lwmutex->owner.GetOwner();
lwmutex->pad = 0;

View File

@ -175,15 +175,16 @@ bool ELF32Loader::LoadShdrInfo()
for(u32 i=0; i<shdr_arr.GetCount(); ++i)
{
elf32_f.Seek(shdr_arr[ehdr.e_shstrndx].sh_offset + shdr_arr[i].sh_name);
wxString name = wxEmptyString;
Array<char> name;
while(!elf32_f.Eof())
{
char c;
elf32_f.Read(&c, 1);
if(c == 0) break;
name += c;
name.AddCpy(c);
}
shdr_name_arr.Add(name);
name.AddCpy('\0');
shdr_name_arr.Add(wxString(name.GetPtr(), wxConvUTF8));
}
return true;

View File

@ -176,16 +176,16 @@ bool ELF64Loader::LoadShdrInfo(s64 offset)
for(u32 i=0; i<shdr_arr.GetCount(); ++i)
{
elf64_f.Seek((offset < 0 ? shdr_arr[ehdr.e_shstrndx].sh_offset : shdr_arr[ehdr.e_shstrndx].sh_offset - ehdr.e_shoff + offset) + shdr_arr[i].sh_name);
wxString name = wxEmptyString;
Array<char> name;
while(!elf64_f.Eof())
{
char c;
elf64_f.Read(&c, 1);
if(c == 0) break;
name += c;
name.AddCpy(c);
}
shdr_name_arr.Add(name);
name.AddCpy('\0');
shdr_name_arr.Add(wxString(name.GetPtr(), wxConvUTF8));
}
return true;