mirror of
https://github.com/SysRay/psOff_public.git
synced 2024-11-23 22:39:40 +00:00
commit
0a3c8a49dd
@ -15,7 +15,9 @@ jmpEntry PROC
|
|||||||
AND RSP, -10h
|
AND RSP, -10h
|
||||||
|
|
||||||
; copy entry param to stack
|
; copy entry param to stack
|
||||||
ADD RSP, 24
|
ADD RSP, 40
|
||||||
|
push [RSI+24]
|
||||||
|
push [RSI+16]
|
||||||
push [RSI+8]
|
push [RSI+8]
|
||||||
push [RSI]
|
push [RSI]
|
||||||
; -
|
; -
|
||||||
|
@ -255,7 +255,7 @@ int DirectMemory::free(off_t start, size_t len) {
|
|||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itHeap->first != addr || itHeap->second.size != len) {
|
if (len != 0 && (itHeap->first != addr || itHeap->second.size != len)) {
|
||||||
LOG_ERR(L"free Error| start:0x%08llx len:0x%08llx != start:0x%08llx len:0x%08llx", addr, len, itHeap->first, itHeap->second.size);
|
LOG_ERR(L"free Error| start:0x%08llx len:0x%08llx != start:0x%08llx len:0x%08llx", addr, len, itHeap->first, itHeap->second.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,8 +313,9 @@ int DirectMemory::map(uint64_t vaddr, off_t offset, size_t len, int prot, int fl
|
|||||||
MemoryInfo* info = nullptr;
|
MemoryInfo* info = nullptr;
|
||||||
if (flags & (int)filesystem::SceMapMode::FIXED) {
|
if (flags & (int)filesystem::SceMapMode::FIXED) {
|
||||||
for (auto& item: m_objects) {
|
for (auto& item: m_objects) {
|
||||||
if (item.second.state == MemoryState::Reserved && item.first <= vaddr && (item.first + item.second.size) > (vaddr + len)) {
|
if (item.second.state == MemoryState::Reserved && item.first <= vaddr && item.second.size >= len) {
|
||||||
info = &item.second;
|
info = &item.second;
|
||||||
|
desVaddr = info->addr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,7 +325,7 @@ int DirectMemory::map(uint64_t vaddr, off_t offset, size_t len, int prot, int fl
|
|||||||
// -
|
// -
|
||||||
|
|
||||||
// Check if Commit needed
|
// Check if Commit needed
|
||||||
if (info->state == MemoryState::Free) {
|
if (info->state == MemoryState::Free || info->state == MemoryState::Reserved) {
|
||||||
MEM_ADDRESS_REQUIREMENTS addressReqs = {0};
|
MEM_ADDRESS_REQUIREMENTS addressReqs = {0};
|
||||||
MEM_EXTENDED_PARAMETER extendedParams = {0};
|
MEM_EXTENDED_PARAMETER extendedParams = {0};
|
||||||
|
|
||||||
@ -335,8 +336,11 @@ int DirectMemory::map(uint64_t vaddr, off_t offset, size_t len, int prot, int fl
|
|||||||
extendedParams.Type = MemExtendedParameterAddressRequirements;
|
extendedParams.Type = MemExtendedParameterAddressRequirements;
|
||||||
extendedParams.Pointer = &addressReqs;
|
extendedParams.Pointer = &addressReqs;
|
||||||
|
|
||||||
void* ptr = VirtualAlloc2(NULL, (void*)desVaddr, info->size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, convProtection(prot),
|
uint32_t flags = MEM_COMMIT;
|
||||||
desVaddr != 0 ? 0 : &extendedParams, desVaddr != 0 ? 0 : 1);
|
if (info->state != MemoryState::Reserved) {
|
||||||
|
flags |= MEM_RESERVE | MEM_WRITE_WATCH;
|
||||||
|
}
|
||||||
|
void* ptr = VirtualAlloc2(NULL, (void*)desVaddr, info->size, flags, convProtection(prot), desVaddr != 0 ? 0 : &extendedParams, desVaddr != 0 ? 0 : 1);
|
||||||
if (ptr == 0) {
|
if (ptr == 0) {
|
||||||
auto const err = GetLastError();
|
auto const err = GetLastError();
|
||||||
LOG_ERR(L"Commit Error| addr:0x%08llx len:0x%08llx err:%d", info->addr, info->size, GetLastError());
|
LOG_ERR(L"Commit Error| addr:0x%08llx len:0x%08llx err:%d", info->addr, info->size, GetLastError());
|
||||||
@ -432,10 +436,32 @@ uint64_t DirectMemory::size() const {
|
|||||||
|
|
||||||
int DirectMemory::getAvailableSize(uint32_t start, uint32_t end, size_t alignment, uint32_t* startOut, size_t* sizeOut) const {
|
int DirectMemory::getAvailableSize(uint32_t start, uint32_t end, size_t alignment, uint32_t* startOut, size_t* sizeOut) const {
|
||||||
LOG_USE_MODULE(DirectMemory);
|
LOG_USE_MODULE(DirectMemory);
|
||||||
LOG_DEBUG(L"availableSize: start:0x%08llx end:0x%08llx alignment:0x%08llx", start, end, alignment);
|
LOG_DEBUG(L"availableSize: start:0x%lx end:0x%lx alignment:0x%08llx", start, end, alignment);
|
||||||
|
|
||||||
*startOut = m_usedSize;
|
auto itItem = m_objects.lower_bound(DIRECTMEM_START + start);
|
||||||
*sizeOut = SCE_KERNEL_MAIN_DMEM_SIZE - m_usedSize;
|
if (m_objects.empty() || itItem == m_objects.end()) {
|
||||||
|
*startOut = start;
|
||||||
|
*sizeOut = std::min(SCE_KERNEL_MAIN_DMEM_SIZE, (uint64_t)end - start);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
*startOut = start;
|
||||||
|
*sizeOut = (itItem->second.addr - DIRECTMEM_START) - start;
|
||||||
|
// if (itItem->second.addr + itItem->second.size >= DIRECTMEM_START + end) {
|
||||||
|
// *startOut = end;
|
||||||
|
// *sizeOut = 0;
|
||||||
|
// return Ok;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// *startOut = start;
|
||||||
|
// *sizeOut = 0;
|
||||||
|
|
||||||
|
// auto itEnd = m_objects.lower_bound(DIRECTMEM_START + end);
|
||||||
|
// for (; itItem != itEnd; ++itItem) {
|
||||||
|
// *startOut = (itItem->second.addr + itItem->second.size) - DIRECTMEM_START;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (*startOut > end) *sizeOut = end - *startOut;
|
||||||
|
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
@ -220,6 +220,8 @@ class FileManager: public IFileManager {
|
|||||||
|
|
||||||
if ((*dir->m_file) == endDir) return 0;
|
if ((*dir->m_file) == endDir) return 0;
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
struct DataStruct {
|
struct DataStruct {
|
||||||
uint32_t fileno;
|
uint32_t fileno;
|
||||||
uint16_t reclen;
|
uint16_t reclen;
|
||||||
@ -228,6 +230,8 @@ class FileManager: public IFileManager {
|
|||||||
char name[256];
|
char name[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop, 1)
|
||||||
|
|
||||||
auto count = dir->count;
|
auto count = dir->count;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
@ -237,7 +241,7 @@ class FileManager: public IFileManager {
|
|||||||
auto const filename = (*dir->m_file)->path().filename().string();
|
auto const filename = (*dir->m_file)->path().filename().string();
|
||||||
if (sizeof(DataStruct) + std::min(filename.size(), 255llu) >= nbytes) break;
|
if (sizeof(DataStruct) + std::min(filename.size(), 255llu) >= nbytes) break;
|
||||||
|
|
||||||
item->fileno = 0;
|
item->fileno = count;
|
||||||
item->type = ((*dir->m_file)->is_regular_file() ? 8 : 4);
|
item->type = ((*dir->m_file)->is_regular_file() ? 8 : 4);
|
||||||
item->namlen = filename.copy(item->name, 255);
|
item->namlen = filename.copy(item->name, 255);
|
||||||
item->name[item->namlen] = '\0';
|
item->name[item->namlen] = '\0';
|
||||||
@ -245,7 +249,7 @@ class FileManager: public IFileManager {
|
|||||||
n += sizeof(DataStruct);
|
n += sizeof(DataStruct);
|
||||||
item->reclen = sizeof(DataStruct);
|
item->reclen = sizeof(DataStruct);
|
||||||
|
|
||||||
LOG_DEBUG(L"KernelGetdirentries[%d]: %S %u offset:%u count:%u", handle, item->name, item->type, item->reclen, count);
|
LOG_DEBUG(L"KernelGetdirentries[%d]: %S %u offset:%u count:%u", handle, item->name, item->type, n, count);
|
||||||
|
|
||||||
std::error_code err;
|
std::error_code err;
|
||||||
(*dir->m_file).increment(err);
|
(*dir->m_file).increment(err);
|
||||||
|
@ -400,11 +400,13 @@ int join(ScePthread_obj obj, void** value) {
|
|||||||
auto thread = getPthread(obj);
|
auto thread = getPthread(obj);
|
||||||
thread->p.join();
|
thread->p.join();
|
||||||
|
|
||||||
|
if (!thread->detached) {
|
||||||
LOG_USE_MODULE(pthread);
|
LOG_USE_MODULE(pthread);
|
||||||
LOG_DEBUG(L"Delete thread:%d", thread->unique_id);
|
LOG_DEBUG(L"Delete thread:%d", thread->unique_id);
|
||||||
// Cleanup thread
|
// Cleanup thread
|
||||||
thread->~PthreadPrivate();
|
thread->~PthreadPrivate();
|
||||||
delete[] obj;
|
delete[] obj;
|
||||||
|
}
|
||||||
// -
|
// -
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
@ -802,10 +804,7 @@ int cancel(ScePthread_obj obj) {
|
|||||||
auto thread = getPthread(obj);
|
auto thread = getPthread(obj);
|
||||||
// todo cancel
|
// todo cancel
|
||||||
// int result = ::pthread_cancel(thread->p);
|
// int result = ::pthread_cancel(thread->p);
|
||||||
|
thread->p.interrupt();
|
||||||
LOG_USE_MODULE(pthread);
|
|
||||||
LOG_ERR(L" todo cancel| %S id:%d", thread->name.data(), thread->unique_id);
|
|
||||||
// LOG_TRACE(L"thread cancel| threadId:%d name:%S result:%d", thread->unique_id, thread->name.c_str(), result);
|
|
||||||
|
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
@ -1219,6 +1218,7 @@ void cleanup_thread() {
|
|||||||
func(arg);
|
func(arg);
|
||||||
thread->cleanupFuncs.pop_back();
|
thread->cleanupFuncs.pop_back();
|
||||||
}
|
}
|
||||||
|
accessRuntimeLinker().destroyTLSKeys(getSelf());
|
||||||
|
|
||||||
auto thread_dtors = *getThreadDtors();
|
auto thread_dtors = *getThreadDtors();
|
||||||
|
|
||||||
@ -1226,8 +1226,6 @@ void cleanup_thread() {
|
|||||||
thread_dtors();
|
thread_dtors();
|
||||||
}
|
}
|
||||||
|
|
||||||
accessRuntimeLinker().destroyTLSKeys(getSelf());
|
|
||||||
|
|
||||||
accessMemoryManager()->unregisterStack((uint64_t)thread->attr.getStackAddr());
|
accessMemoryManager()->unregisterStack((uint64_t)thread->attr.getStackAddr());
|
||||||
|
|
||||||
// Delete here if detached, else in join()
|
// Delete here if detached, else in join()
|
||||||
|
@ -691,13 +691,13 @@ void RuntimeLinker::destroyTLSKeys(uint8_t* obj) {
|
|||||||
|
|
||||||
std::unique_lock const lock(m_mutex_int);
|
std::unique_lock const lock(m_mutex_int);
|
||||||
|
|
||||||
m_threadList.erase(pthread::getThreadId(obj));
|
|
||||||
|
|
||||||
for (uint64_t n = m_countcreatePrograms; n < m_dtvKeys.size(); ++n, ++pDtvKey) {
|
for (uint64_t n = m_countcreatePrograms; n < m_dtvKeys.size(); ++n, ++pDtvKey) {
|
||||||
if (m_dtvKeys[n].destructor != nullptr) {
|
if (m_dtvKeys[n].destructor != nullptr) {
|
||||||
m_dtvKeys[n].destructor((void*)pDtvKey[n]);
|
if (pDtvKey[n] != 0) m_dtvKeys[n].destructor((void*)pDtvKey[n]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_threadList.erase(pthread::getThreadId(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeLinker::stopModules() {
|
void RuntimeLinker::stopModules() {
|
||||||
|
@ -19,8 +19,8 @@ struct PortOut {
|
|||||||
int userId = 0;
|
int userId = 0;
|
||||||
SceAudioOutPortType type = SceAudioOutPortType::MAIN;
|
SceAudioOutPortType type = SceAudioOutPortType::MAIN;
|
||||||
uint8_t sampleSize = 0;
|
uint8_t sampleSize = 0;
|
||||||
|
uint32_t sampleRate = 0;
|
||||||
uint32_t samplesNum = 0;
|
uint32_t samplesNum = 0;
|
||||||
uint32_t freq = 0;
|
|
||||||
uint32_t queued = 0;
|
uint32_t queued = 0;
|
||||||
SceAudioOutParamFormat format = SceAudioOutParamFormat::FLOAT_MONO;
|
SceAudioOutParamFormat format = SceAudioOutParamFormat::FLOAT_MONO;
|
||||||
uint64_t lastOutputTime = 0;
|
uint64_t lastOutputTime = 0;
|
||||||
@ -31,6 +31,8 @@ struct PortOut {
|
|||||||
float volumeModifier = 0.5f;
|
float volumeModifier = 0.5f;
|
||||||
std::vector<uint8_t> mixedAudio;
|
std::vector<uint8_t> mixedAudio;
|
||||||
std::string deviceName;
|
std::string deviceName;
|
||||||
|
|
||||||
|
SDL_AudioSpec audioSpec;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PortsOut {
|
class PortsOut {
|
||||||
@ -70,16 +72,7 @@ class PortsOut {
|
|||||||
*/
|
*/
|
||||||
if (port.deviceName.compare(0, std::string::npos, devName, 0, port.deviceName.length()) != 0) continue;
|
if (port.deviceName.compare(0, std::string::npos, devName, 0, port.deviceName.length()) != 0) continue;
|
||||||
|
|
||||||
SDL_AudioSpec fmt {
|
if ((port.device = SDL_OpenAudioDevice(devName, 0, &port.audioSpec, NULL, 0)) == 0) {
|
||||||
.freq = static_cast<int>(port.freq),
|
|
||||||
.format = port.sdlFormat,
|
|
||||||
.channels = static_cast<uint8_t>(port.channelsNum),
|
|
||||||
.samples = static_cast<uint16_t>(port.samplesNum),
|
|
||||||
.callback = nullptr,
|
|
||||||
.userdata = nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
if ((port.device = SDL_OpenAudioDevice(devName, 0, &fmt, NULL, 0)) == 0) {
|
|
||||||
LOG_ERR(L"Failed to reopen %S audio device: %S", devName, SDL_GetError());
|
LOG_ERR(L"Failed to reopen %S audio device: %S", devName, SDL_GetError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -167,7 +160,7 @@ void syncPort(PortOut* port) {
|
|||||||
const uint32_t bytesize = bytesize_1ch * port->channelsNum;
|
const uint32_t bytesize = bytesize_1ch * port->channelsNum;
|
||||||
|
|
||||||
if (port->device == 0) {
|
if (port->device == 0) {
|
||||||
float duration = bytesize_1ch / float(port->freq * port->sampleSize);
|
float duration = bytesize_1ch / float(port->sampleRate * port->sampleSize);
|
||||||
SDL_Delay(int(duration * 1000)); // Pretending that we playing something
|
SDL_Delay(int(duration * 1000)); // Pretending that we playing something
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -200,12 +193,11 @@ int writeOut(PortOut* port, const void* ptr, bool sync = true) {
|
|||||||
return port->samplesNum;
|
return port->samplesNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t bytesize = bytesize_1ch * port->channelsNum;
|
|
||||||
const int maxVolume = SDL_MIX_MAXVOLUME * port->volumeModifier;
|
const int maxVolume = SDL_MIX_MAXVOLUME * port->volumeModifier;
|
||||||
auto& mixed = port->mixedAudio;
|
auto& mixed = port->mixedAudio;
|
||||||
std::fill(mixed.begin(), mixed.end(), 0);
|
std::fill(mixed.begin(), mixed.end(), 0);
|
||||||
|
|
||||||
for (int i = 0; i < port->channelsNum; i++) {
|
for (int i = 0; i < port->audioSpec.channels; i++) {
|
||||||
auto ch_offset = i * bytesize_1ch;
|
auto ch_offset = i * bytesize_1ch;
|
||||||
SDL_MixAudioFormat(mixed.data() + ch_offset, ((const uint8_t*)ptr) + ch_offset, port->sdlFormat, bytesize_1ch,
|
SDL_MixAudioFormat(mixed.data() + ch_offset, ((const uint8_t*)ptr) + ch_offset, port->sdlFormat, bytesize_1ch,
|
||||||
maxVolume * ((float)port->volume[i] / AudioOut::VOLUME_0DB));
|
maxVolume * ((float)port->volume[i] / AudioOut::VOLUME_0DB));
|
||||||
@ -213,7 +205,7 @@ int writeOut(PortOut* port, const void* ptr, bool sync = true) {
|
|||||||
|
|
||||||
if (SDL_GetAudioDeviceStatus(port->device) != SDL_AUDIO_PLAYING) SDL_PauseAudioDevice(port->device, 0);
|
if (SDL_GetAudioDeviceStatus(port->device) != SDL_AUDIO_PLAYING) SDL_PauseAudioDevice(port->device, 0);
|
||||||
|
|
||||||
int ret = SDL_QueueAudio(port->device, mixed.data(), bytesize);
|
int ret = SDL_QueueAudio(port->device, mixed.data(), port->audioSpec.size);
|
||||||
if (ret == 0) port->queued = SDL_GetQueuedAudioSize(port->device);
|
if (ret == 0) port->queued = SDL_GetQueuedAudioSize(port->device);
|
||||||
if (sync) syncPort(port);
|
if (sync) syncPort(port);
|
||||||
|
|
||||||
@ -237,7 +229,7 @@ EXPORT SYSV_ABI int32_t sceAudioOutInit(void) {
|
|||||||
return Err::AudioOut::OUT_OF_MEMORY;
|
return Err::AudioOut::OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceAudioOutOpen(int32_t userId, SceAudioOutPortType type, int32_t index, uint32_t len, uint32_t freq, uint32_t param) {
|
EXPORT SYSV_ABI int32_t sceAudioOutOpen(int32_t userId, SceAudioOutPortType type, int32_t index, uint32_t numSamples, uint32_t sampleRate, uint32_t param) {
|
||||||
if (!audioInited) return Err::AudioOut::NOT_INIT;
|
if (!audioInited) return Err::AudioOut::NOT_INIT;
|
||||||
LOG_USE_MODULE(libSceAudioOut);
|
LOG_USE_MODULE(libSceAudioOut);
|
||||||
LOG_TRACE(L"%S", __FUNCTION__);
|
LOG_TRACE(L"%S", __FUNCTION__);
|
||||||
@ -260,8 +252,8 @@ EXPORT SYSV_ABI int32_t sceAudioOutOpen(int32_t userId, SceAudioOutPortType type
|
|||||||
int handle;
|
int handle;
|
||||||
if (auto port = pimpl->portsOut.AcquirePort(type, &handle)) {
|
if (auto port = pimpl->portsOut.AcquirePort(type, &handle)) {
|
||||||
port->userId = userId;
|
port->userId = userId;
|
||||||
port->samplesNum = len;
|
port->samplesNum = numSamples;
|
||||||
port->freq = freq;
|
port->sampleRate = sampleRate;
|
||||||
port->format = SceAudioOutParamFormat(param & 0x0000007F);
|
port->format = SceAudioOutParamFormat(param & 0x0000007F);
|
||||||
|
|
||||||
if ((param & 0x000F0000) != 0) {
|
if ((param & 0x000F0000) != 0) {
|
||||||
@ -322,6 +314,15 @@ EXPORT SYSV_ABI int32_t sceAudioOutOpen(int32_t userId, SceAudioOutPortType type
|
|||||||
port->volumeModifier = 0.5f;
|
port->volumeModifier = 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_AudioSpec audioSpec = {
|
||||||
|
.freq = static_cast<int>(sampleRate),
|
||||||
|
.format = port->sdlFormat,
|
||||||
|
.channels = static_cast<uint8_t>(port->channelsNum),
|
||||||
|
.samples = static_cast<uint16_t>(port->samplesNum),
|
||||||
|
.callback = nullptr,
|
||||||
|
.userdata = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
if (type == SceAudioOutPortType::PADSPK) {
|
if (type == SceAudioOutPortType::PADSPK) {
|
||||||
auto& devn = (*jData)["padspeakers"][userId - 1];
|
auto& devn = (*jData)["padspeakers"][userId - 1];
|
||||||
|
|
||||||
@ -344,9 +345,8 @@ EXPORT SYSV_ABI int32_t sceAudioOutOpen(int32_t userId, SceAudioOutPortType type
|
|||||||
port->volume[i] = AudioOut::MIXLEVEL_PADSPK_0DB;
|
port->volume[i] = AudioOut::MIXLEVEL_PADSPK_0DB;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SDL_AudioSpec fmt_curr;
|
|
||||||
if ((*jData)["device"] == "[default]") {
|
if ((*jData)["device"] == "[default]") {
|
||||||
if (SDL_GetDefaultAudioInfo((char**)&dname, &fmt_curr, 0) != 0) {
|
if (SDL_GetDefaultAudioInfo((char**)&dname, &port->audioSpec, 0) != 0) {
|
||||||
LOG_ERR(L"Failed to get the default audio device, port #%d is nulled! (%S)", handle, SDL_GetError());
|
LOG_ERR(L"Failed to get the default audio device, port #%d is nulled! (%S)", handle, SDL_GetError());
|
||||||
port->device = 0;
|
port->device = 0;
|
||||||
return handle;
|
return handle;
|
||||||
@ -362,7 +362,7 @@ EXPORT SYSV_ABI int32_t sceAudioOutOpen(int32_t userId, SceAudioOutPortType type
|
|||||||
} catch (const json::exception& e) {
|
} catch (const json::exception& e) {
|
||||||
LOG_ERR(L"Invalid audio device name: %S, falling back to default", e.what());
|
LOG_ERR(L"Invalid audio device name: %S, falling back to default", e.what());
|
||||||
dname = NULL;
|
dname = NULL;
|
||||||
if (SDL_GetDefaultAudioInfo((char**)&dname, &fmt_curr, 0) != 0) {
|
if (SDL_GetDefaultAudioInfo((char**)&dname, &port->audioSpec, 0) != 0) {
|
||||||
LOG_ERR(L"Falling back to default device failed, port #%d is nulled! (%S)", handle, SDL_GetError());
|
LOG_ERR(L"Falling back to default device failed, port #%d is nulled! (%S)", handle, SDL_GetError());
|
||||||
port->device = 0;
|
port->device = 0;
|
||||||
return handle;
|
return handle;
|
||||||
@ -375,16 +375,7 @@ EXPORT SYSV_ABI int32_t sceAudioOutOpen(int32_t userId, SceAudioOutPortType type
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_AudioSpec fmt {
|
if ((port->device = SDL_OpenAudioDevice(dname, 0, &audioSpec, &port->audioSpec, 0)) == 0) {
|
||||||
.freq = static_cast<int>(freq),
|
|
||||||
.format = port->sdlFormat,
|
|
||||||
.channels = static_cast<uint8_t>(port->channelsNum),
|
|
||||||
.samples = static_cast<uint16_t>(port->samplesNum),
|
|
||||||
.callback = nullptr,
|
|
||||||
.userdata = nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
if ((port->device = SDL_OpenAudioDevice(dname, 0, &fmt, NULL, 0)) == 0) {
|
|
||||||
LOG_ERR(L"Failed to open %S audio device: %S", getDevName(type), SDL_GetError());
|
LOG_ERR(L"Failed to open %S audio device: %S", getDevName(type), SDL_GetError());
|
||||||
// Since audio connect/disconnect event is implemented now, we can fall through there.
|
// Since audio connect/disconnect event is implemented now, we can fall through there.
|
||||||
// The audio device will be opened automatically when available.
|
// The audio device will be opened automatically when available.
|
||||||
@ -392,7 +383,7 @@ EXPORT SYSV_ABI int32_t sceAudioOutOpen(int32_t userId, SceAudioOutPortType type
|
|||||||
LOG_INFO(L"%S audio device %S opened for user #%d", getDevName(type), dname, userId);
|
LOG_INFO(L"%S audio device %S opened for user #%d", getDevName(type), dname, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
port->mixedAudio.resize(port->sampleSize * port->samplesNum * port->channelsNum);
|
port->mixedAudio.resize(port->audioSpec.size);
|
||||||
port->deviceName.assign(dname);
|
port->deviceName.assign(dname);
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,7 @@ class Avplayer: public IAvplayer {
|
|||||||
std::array<void*, 4> m_videoPlane;
|
std::array<void*, 4> m_videoPlane;
|
||||||
|
|
||||||
int64_t m_startTime = 0;
|
int64_t m_startTime = 0;
|
||||||
|
uint64_t m_latestTimestamp = 0;
|
||||||
|
|
||||||
// Avplayer Data
|
// Avplayer Data
|
||||||
AVFormatContext* m_pFmtCtx = nullptr;
|
AVFormatContext* m_pFmtCtx = nullptr;
|
||||||
@ -172,6 +173,8 @@ class Avplayer: public IAvplayer {
|
|||||||
return m_isVideoActive || m_isAudioActive;
|
return m_isVideoActive || m_isAudioActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t getCurrentTime() const final { return m_latestTimestamp; }
|
||||||
|
|
||||||
void stop() final {
|
void stop() final {
|
||||||
LOG_USE_MODULE(AvPlayer);
|
LOG_USE_MODULE(AvPlayer);
|
||||||
LOG_DEBUG(L"stop");
|
LOG_DEBUG(L"stop");
|
||||||
@ -279,7 +282,9 @@ bool Avplayer::getVideoData(void* info, bool isEx) {
|
|||||||
if (retRecv < 0) {
|
if (retRecv < 0) {
|
||||||
if (retRecv == AVERROR(EAGAIN)) {
|
if (retRecv == AVERROR(EAGAIN)) {
|
||||||
if (!m_isStop) {
|
if (!m_isStop) {
|
||||||
|
LOG_TRACE(L"-> wait video frame");
|
||||||
m_video.m_cond.wait(lock);
|
m_video.m_cond.wait(lock);
|
||||||
|
LOG_TRACE(L"<- wait video frame");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (retRecv != AVERROR_EOF) {
|
} else if (retRecv != AVERROR_EOF) {
|
||||||
@ -310,10 +315,13 @@ bool Avplayer::getVideoData(void* info, bool isEx) {
|
|||||||
auto const timestamp = (int64_t)(1000.0 * av_q2d(m_video.stream->time_base) * m_video.frame->best_effort_timestamp); // timestamp[seconds] to [ms]
|
auto const timestamp = (int64_t)(1000.0 * av_q2d(m_video.stream->time_base) * m_video.frame->best_effort_timestamp); // timestamp[seconds] to [ms]
|
||||||
|
|
||||||
auto const curTime = (av_gettime() - m_startTime) / 1000; // [us] to [ms]
|
auto const curTime = (av_gettime() - m_startTime) / 1000; // [us] to [ms]
|
||||||
|
LOG_TRACE(L"video frame timestamp:%lld", curTime);
|
||||||
if (timestamp > curTime) {
|
if (timestamp > curTime) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_latestTimestamp = timestamp;
|
||||||
|
|
||||||
LOG_DEBUG(L"Received video frame, timestamp:%lld", m_video.frame->pts);
|
LOG_DEBUG(L"Received video frame, timestamp:%lld", m_video.frame->pts);
|
||||||
m_video.getNewFrame = true;
|
m_video.getNewFrame = true;
|
||||||
|
|
||||||
@ -385,7 +393,9 @@ bool Avplayer::getAudioData(SceAvPlayerFrameInfo* info) {
|
|||||||
if (retRecv < 0) {
|
if (retRecv < 0) {
|
||||||
if (retRecv == AVERROR(EAGAIN)) {
|
if (retRecv == AVERROR(EAGAIN)) {
|
||||||
if (!m_isStop) {
|
if (!m_isStop) {
|
||||||
|
LOG_TRACE(L"-> wait audio frame");
|
||||||
m_audio.m_cond.wait(lock);
|
m_audio.m_cond.wait(lock);
|
||||||
|
LOG_TRACE(L"<- wait audio frame");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (retRecv != AVERROR_EOF) {
|
} else if (retRecv != AVERROR_EOF) {
|
||||||
@ -410,6 +420,7 @@ bool Avplayer::getAudioData(SceAvPlayerFrameInfo* info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto const timestamp = (int64_t)(1000.0 * av_q2d(m_audio.stream->time_base) * m_audio.frame->best_effort_timestamp); // timestamp[seconds] to [ms]
|
auto const timestamp = (int64_t)(1000.0 * av_q2d(m_audio.stream->time_base) * m_audio.frame->best_effort_timestamp); // timestamp[seconds] to [ms]
|
||||||
|
m_latestTimestamp = timestamp;
|
||||||
|
|
||||||
// Convert and copy
|
// Convert and copy
|
||||||
int const outNumSamples = swr_get_out_samples(m_swrCtx, m_audio.frame->nb_samples);
|
int const outNumSamples = swr_get_out_samples(m_swrCtx, m_audio.frame->nb_samples);
|
||||||
@ -522,7 +533,7 @@ std::unique_ptr<std::thread> Avplayer::threadFunc() {
|
|||||||
LOG_DEBUG(L"Queue Video Packet: numItems:%llu pts:%lld", m_video.decodeQueue.size(), packet->pts);
|
LOG_DEBUG(L"Queue Video Packet: numItems:%llu pts:%lld", m_video.decodeQueue.size(), packet->pts);
|
||||||
} else if (packet->stream_index == m_audio.streamIndex) {
|
} else if (packet->stream_index == m_audio.streamIndex) {
|
||||||
m_audio.decodeQueue.push(packet);
|
m_audio.decodeQueue.push(packet);
|
||||||
LOG_DEBUG(L"Queue Video Packet: numItems:%llu pts:%lld", m_video.decodeQueue.size(), packet->pts);
|
LOG_DEBUG(L"Queue Audio Packet: numItems:%llu pts:%lld", m_audio.decodeQueue.size(), packet->pts);
|
||||||
} else
|
} else
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,13 @@ class IAvplayer {
|
|||||||
virtual bool isPlaying() = 0;
|
virtual bool isPlaying() = 0;
|
||||||
virtual void stop() = 0;
|
virtual void stop() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the latest timestamp
|
||||||
|
*
|
||||||
|
* @return uint64_t [ms]
|
||||||
|
*/
|
||||||
|
virtual uint64_t getCurrentTime() const = 0;
|
||||||
|
|
||||||
virtual ~IAvplayer() = default;
|
virtual ~IAvplayer() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,39 +30,57 @@ EXPORT SYSV_ABI int32_t sceAvPlayerAddSource(IAvplayer* avPlayer, const char* fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceAvPlayerStreamCount(IAvplayer* avPlayer) {
|
EXPORT SYSV_ABI int32_t sceAvPlayerStreamCount(IAvplayer* avPlayer) {
|
||||||
|
LOG_USE_MODULE(libSceAvPlayer);
|
||||||
|
LOG_ERR(L"todo %S", __FUNCTION__);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceAvPlayerGetStreamInfo(IAvplayer* avPlayer, uint32_t argStreamID, SceAvPlayerStreamInfo* argInfo) {
|
EXPORT SYSV_ABI int32_t sceAvPlayerGetStreamInfo(IAvplayer* avPlayer, uint32_t argStreamID, SceAvPlayerStreamInfo* argInfo) {
|
||||||
|
LOG_USE_MODULE(libSceAvPlayer);
|
||||||
|
LOG_ERR(L"todo %S", __FUNCTION__);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceAvPlayerEnableStream(IAvplayer* avPlayer, uint32_t argStreamID) {
|
EXPORT SYSV_ABI int32_t sceAvPlayerEnableStream(IAvplayer* avPlayer, uint32_t argStreamID) {
|
||||||
|
LOG_USE_MODULE(libSceAvPlayer);
|
||||||
|
LOG_ERR(L"todo %S", __FUNCTION__);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceAvPlayerDisableStream(IAvplayer* avPlayer, uint32_t argStreamID) {
|
EXPORT SYSV_ABI int32_t sceAvPlayerDisableStream(IAvplayer* avPlayer, uint32_t argStreamID) {
|
||||||
|
LOG_USE_MODULE(libSceAvPlayer);
|
||||||
|
LOG_ERR(L"todo %S", __FUNCTION__);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceAvPlayerChangeStream(IAvplayer* avPlayer, uint32_t argOldStreamID, uint32_t argNewStreamID) {
|
EXPORT SYSV_ABI int32_t sceAvPlayerChangeStream(IAvplayer* avPlayer, uint32_t argOldStreamID, uint32_t argNewStreamID) {
|
||||||
|
LOG_USE_MODULE(libSceAvPlayer);
|
||||||
|
LOG_ERR(L"todo %S", __FUNCTION__);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceAvPlayerStart(IAvplayer* avPlayer) {
|
EXPORT SYSV_ABI int32_t sceAvPlayerStart(IAvplayer* avPlayer) {
|
||||||
|
LOG_USE_MODULE(libSceAvPlayer);
|
||||||
|
LOG_ERR(L"todo %S", __FUNCTION__);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceAvPlayerStop(IAvplayer* avPlayer) {
|
EXPORT SYSV_ABI int32_t sceAvPlayerStop(IAvplayer* avPlayer) {
|
||||||
|
LOG_USE_MODULE(libSceAvPlayer);
|
||||||
|
LOG_ERR(L"todo %S", __FUNCTION__);
|
||||||
avPlayer->stop();
|
avPlayer->stop();
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceAvPlayerPause(IAvplayer* avPlayer) {
|
EXPORT SYSV_ABI int32_t sceAvPlayerPause(IAvplayer* avPlayer) {
|
||||||
|
LOG_USE_MODULE(libSceAvPlayer);
|
||||||
|
LOG_ERR(L"todo %S", __FUNCTION__);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceAvPlayerResume(IAvplayer* avPlayer) {
|
EXPORT SYSV_ABI int32_t sceAvPlayerResume(IAvplayer* avPlayer) {
|
||||||
|
LOG_USE_MODULE(libSceAvPlayer);
|
||||||
|
LOG_ERR(L"todo %S", __FUNCTION__);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,18 +103,24 @@ EXPORT SYSV_ABI bool sceAvPlayerGetVideoData(IAvplayer* avPlayer, SceAvPlayerFra
|
|||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI uint64_t sceAvPlayerCurrentTime(IAvplayer* avPlayer) {
|
EXPORT SYSV_ABI uint64_t sceAvPlayerCurrentTime(IAvplayer* avPlayer) {
|
||||||
return Ok;
|
return avPlayer->getCurrentTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceAvPlayerJumpToTime(IAvplayer* avPlayer, uint64_t argJumpTimeMsec) {
|
EXPORT SYSV_ABI int32_t sceAvPlayerJumpToTime(IAvplayer* avPlayer, uint64_t argJumpTimeMsec) {
|
||||||
|
LOG_USE_MODULE(libSceAvPlayer);
|
||||||
|
LOG_ERR(L"todo %S", __FUNCTION__);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceAvPlayerSetTrickSpeed(IAvplayer* avPlayer, int32_t argTrickSpeed) {
|
EXPORT SYSV_ABI int32_t sceAvPlayerSetTrickSpeed(IAvplayer* avPlayer, int32_t argTrickSpeed) {
|
||||||
|
LOG_USE_MODULE(libSceAvPlayer);
|
||||||
|
LOG_ERR(L"todo %S", __FUNCTION__);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceAvPlayerSetAvSyncMode(IAvplayer* avPlayer, SceAvPlayerAvSyncMode argSyncMode) {
|
EXPORT SYSV_ABI int32_t sceAvPlayerSetAvSyncMode(IAvplayer* avPlayer, SceAvPlayerAvSyncMode argSyncMode) {
|
||||||
|
LOG_USE_MODULE(libSceAvPlayer);
|
||||||
|
LOG_ERR(L"todo %S", __FUNCTION__);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
cmake_minimum_required(VERSION 3.24)
|
cmake_minimum_required(VERSION 3.24)
|
||||||
include(../setupModule.cmake)
|
include(../setupModule.cmake)
|
||||||
|
|
||||||
|
add_compile_definitions(
|
||||||
|
BOOST_ALL_NO_LIB
|
||||||
|
)
|
||||||
|
|
||||||
set(libName libSceNgs2)
|
set(libName libSceNgs2)
|
||||||
project(${libName})
|
project(${libName})
|
||||||
|
|
||||||
add_library(${libName} SHARED entry.cpp)
|
add_library(${libName} SHARED entry.cpp readFuncs.cpp reader.cpp)
|
||||||
|
|
||||||
set(FFMPEG_LIBS
|
set(FFMPEG_LIBS
|
||||||
avformat
|
avformat
|
||||||
@ -15,6 +19,6 @@ set(FFMPEG_LIBS
|
|||||||
)
|
)
|
||||||
|
|
||||||
add_dependencies(${libName} core)
|
add_dependencies(${libName} core)
|
||||||
target_link_libraries(${libName} PRIVATE core.lib ${FFMPEG_LIBS})
|
target_link_libraries(${libName} PRIVATE core.lib ${FFMPEG_LIBS} libboost_thread libboost_chrono)
|
||||||
|
|
||||||
setupModule(${libName})
|
setupModule(${libName})
|
||||||
|
@ -7,6 +7,7 @@ constexpr int32_t INVALID_WAVEFORM_DATA = -2142632952;
|
|||||||
constexpr int32_t INVALID_BUFFER_ADDRESS = -2142633465;
|
constexpr int32_t INVALID_BUFFER_ADDRESS = -2142633465;
|
||||||
constexpr int32_t INVALID_BUFFER_SIZE = -2142633466;
|
constexpr int32_t INVALID_BUFFER_SIZE = -2142633466;
|
||||||
constexpr int32_t INVALID_SYSTEM_HANDLE = -2142633424;
|
constexpr int32_t INVALID_SYSTEM_HANDLE = -2142633424;
|
||||||
|
constexpr int32_t INVALID_VOICE_HANDLE = -2142633216;
|
||||||
constexpr int32_t INVALID_RACK_HANDLE = -2142633375;
|
constexpr int32_t INVALID_RACK_HANDLE = -2142633375;
|
||||||
constexpr int32_t INVALID_VOICE_INDEX = -2142633214;
|
constexpr int32_t INVALID_VOICE_INDEX = -2142633214;
|
||||||
constexpr int32_t INVALID_BUFFER_ALLOCATOR = -2142633462;
|
constexpr int32_t INVALID_BUFFER_ALLOCATOR = -2142633462;
|
||||||
@ -25,4 +26,14 @@ constexpr int32_t SCE_NGS2_MAX_MATRIX_LEVELS = 64;
|
|||||||
constexpr int32_t SCE_NGS2_RACK_NAME_LENGTH = 16;
|
constexpr int32_t SCE_NGS2_RACK_NAME_LENGTH = 16;
|
||||||
constexpr int32_t SCE_NGS2_SYSTEM_NAME_LENGTH = 16;
|
constexpr int32_t SCE_NGS2_SYSTEM_NAME_LENGTH = 16;
|
||||||
|
|
||||||
constexpr int32_t SCE_NGS2_SAMPLER_VOICE_ADD_WAVEFORM_BLOCKS = 0x10000001;
|
constexpr uint16_t SCE_NGS2_RACK_ID_VOICE = 0x0000;
|
||||||
|
constexpr uint16_t SCE_NGS2_RACK_ID_SAMPLER = 0x1000;
|
||||||
|
constexpr uint16_t SCE_NGS2_RACK_ID_SUBMIXER = 0x2000;
|
||||||
|
constexpr uint16_t SCE_NGS2_RACK_ID_MASTERING = 0x3000;
|
||||||
|
|
||||||
|
constexpr uint16_t SCE_NGS2_RACK_ID_REVERB = 0x2001;
|
||||||
|
constexpr uint16_t SCE_NGS2_RACK_ID_EQ = 0x2002;
|
||||||
|
|
||||||
|
constexpr uint16_t SCE_NGS2_RACK_ID_CUSTOM_SAMPLER = 0x4001;
|
||||||
|
constexpr uint16_t SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER = 0x4002;
|
||||||
|
constexpr uint16_t SCE_NGS2_RACK_ID_CUSTOM_MASTERING = 0x4003;
|
@ -1,178 +1,358 @@
|
|||||||
#include "codes.h"
|
#include "core/fileManager/ifile.h"
|
||||||
#include "common.h"
|
|
||||||
extern "C" {
|
|
||||||
#include "libavformat/avformat.h"
|
|
||||||
}
|
|
||||||
#include "core/kernel/filesystem.h"
|
#include "core/kernel/filesystem.h"
|
||||||
#include "core/kernel/pthread.h"
|
#include "core/kernel/pthread.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
#include "readFuncs.h"
|
||||||
|
#include "reader.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
LOG_DEFINE_MODULE(libSceNgs2);
|
LOG_DEFINE_MODULE(libSceNgs2);
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
enum WaveformInfoType {
|
static boost::mutex MUTEX_INT;
|
||||||
WAVEFORM_FILE,
|
|
||||||
WAVEFORM_DATA,
|
struct Impl {
|
||||||
WAVEFORM_USER,
|
std::set<SceNgs2Handle*> handles;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WaveformInfo {
|
Impl* getPimpl() {
|
||||||
WaveformInfoType type;
|
static Impl pimpl;
|
||||||
char pad[4];
|
return &pimpl;
|
||||||
|
}
|
||||||
|
|
||||||
union WaveformPtr {
|
int32_t _voiceControlWaveformBlock(SceNgs2Handle* voh, const SceNgs2SamplerVoiceWaveformBlocksParam* svwfbp) {
|
||||||
int fileHandle;
|
|
||||||
SceWaveformUserFunc* userFunc;
|
|
||||||
const void* dataPtr;
|
|
||||||
} ud;
|
|
||||||
|
|
||||||
size_t size;
|
|
||||||
long offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
static SceNgs2ChannelsCount ParseChanCount(int num) {
|
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
|
||||||
switch (num) {
|
LOG_TRACE(L"waveblock: %d\n", svwfbp->numBlocks);
|
||||||
case 1: return SceNgs2ChannelsCount::CH_1_0;
|
LOG_TRACE(L"waveptr: %llx\n", svwfbp->data);
|
||||||
|
|
||||||
case 2: return SceNgs2ChannelsCount::CH_2_0;
|
if (voh->type != SceNgs2HandleType::Voice) return Err::Ngs2::INVALID_VOICE_HANDLE;
|
||||||
|
auto voice = (SceNgs2Handle_voice*)voh;
|
||||||
|
|
||||||
case 6: return SceNgs2ChannelsCount::CH_5_1;
|
if (voice->reader == nullptr) voice->reader = std::make_unique<Reader>(voice).release();
|
||||||
|
|
||||||
case 8: return SceNgs2ChannelsCount::CH_7_1;
|
// svwfbp->data can be nullptr!
|
||||||
|
if (!voice->reader->init(svwfbp)) {
|
||||||
|
return Err::Ngs2::INVALID_WAVEFORM_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_CRIT(L"Invalid channels count sent to ParseChanCount!");
|
LOG_DEBUG(L"waveptr voice:0x%08llx %llx", (uint64_t)voh, svwfbp->data);
|
||||||
return SceNgs2ChannelsCount::INVALID;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SceNgs2WaveFormType ParseWaveType(AVCodecID codec) {
|
int32_t voiceControl_voice(SceNgs2Handle* voh, const SceNgs2VoiceParamHead* phead) {
|
||||||
switch (codec) {
|
|
||||||
case AVCodecID::AV_CODEC_ID_PCM_S8: return SceNgs2WaveFormType::PCM_I8;
|
|
||||||
|
|
||||||
case AVCodecID::AV_CODEC_ID_PCM_U8: return SceNgs2WaveFormType::PCM_U8;
|
|
||||||
|
|
||||||
case AVCodecID::AV_CODEC_ID_ATRAC9: return SceNgs2WaveFormType::ATRAC9;
|
|
||||||
|
|
||||||
default: return SceNgs2WaveFormType::NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RIFFBuf {
|
|
||||||
const uint8_t* data;
|
|
||||||
size_t size;
|
|
||||||
uint64_t offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int readbuf(void* op, uint8_t* buf, int bufsz) {
|
|
||||||
auto rb = (RIFFBuf*)op;
|
|
||||||
if (rb->offset > rb->size) return AVERROR_EOF;
|
|
||||||
int read = std::min(int(rb->size - rb->offset), bufsz);
|
|
||||||
if (read == 0) return AVERROR_EOF;
|
|
||||||
::memcpy(buf, rb->data + rb->offset, read);
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int64_t seekbuf(void* op, int64_t offset, int whence) {
|
|
||||||
auto rb = (RIFFBuf*)op;
|
|
||||||
if (whence == AVSEEK_SIZE) return rb->size;
|
|
||||||
|
|
||||||
if (rb->data == nullptr || rb->size == 0) return -1;
|
|
||||||
if (whence == SEEK_SET)
|
|
||||||
rb->offset = offset;
|
|
||||||
else if (whence == SEEK_CUR)
|
|
||||||
rb->offset += offset;
|
|
||||||
else if (whence == SEEK_END)
|
|
||||||
rb->offset = rb->size - offset;
|
|
||||||
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t ParseData(const uint8_t* data, size_t size, SceNgs2WaveformFormat* wf) {
|
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
AVFormatContext* fmtctx = avformat_alloc_context();
|
LOG_DEBUG(L"voiceControl_voice id:%u type:%u", phead->id & 0xFFFF, voh->type);
|
||||||
|
|
||||||
auto aBufferIo = (uint8_t*)av_malloc(4096 + AV_INPUT_BUFFER_PADDING_SIZE);
|
if (voh->type != SceNgs2HandleType::Voice) return Err::Ngs2::INVALID_VOICE_HANDLE;
|
||||||
|
auto voice = (SceNgs2Handle_voice*)voh;
|
||||||
|
|
||||||
RIFFBuf rb {
|
switch ((SceNgs2VoiceParam)(phead->id & 0xFFFF)) {
|
||||||
.data = data,
|
case SceNgs2VoiceParam::SET_MATRIX_LEVELS: {
|
||||||
.size = size,
|
} break;
|
||||||
.offset = 0,
|
case SceNgs2VoiceParam::SET_PORT_VOLUME: {
|
||||||
};
|
// todo
|
||||||
|
} break;
|
||||||
AVIOContext* avioctx = avio_alloc_context(aBufferIo, 4096, 0, &rb, &readbuf, nullptr, &seekbuf);
|
case SceNgs2VoiceParam::SET_PORT_MATRIX: {
|
||||||
fmtctx->pb = avioctx;
|
} break;
|
||||||
fmtctx->flags |= AVFMT_FLAG_CUSTOM_IO;
|
case SceNgs2VoiceParam::SET_PORT_DELAY: {
|
||||||
|
} break;
|
||||||
int ret = avformat_open_input(&fmtctx, "nullptr", nullptr, nullptr);
|
case SceNgs2VoiceParam::PATCH: {
|
||||||
if (ret != 0) {
|
auto item = (SceNgs2VoicePatchParam*)phead;
|
||||||
LOG_ERR(L"ParseRIFF: ffmpeg failed to read passed data: %d", ret);
|
// todo
|
||||||
return Err::Ngs2::FAIL;
|
} break;
|
||||||
|
case SceNgs2VoiceParam::KICK_EVENT: {
|
||||||
|
auto item = (SceNgs2VoiceEventParam*)phead;
|
||||||
|
voice->ev_KickEvent((SceNgs2VoiceEvent)item->eventId);
|
||||||
|
} break;
|
||||||
|
case SceNgs2VoiceParam::SET_CALLBACK: {
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
AVStream* astream = nullptr;
|
int32_t voiceControl_mastering(SceNgs2Handle* voh, const SceNgs2VoiceParamHead* phead) {
|
||||||
for (int i = 0; fmtctx->nb_streams; i++) {
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
if (fmtctx->streams[i]->codecpar->codec_type == AVMediaType::AVMEDIA_TYPE_AUDIO) {
|
LOG_DEBUG(L"voiceControl_mastering id:%u type:%u", phead->id & 0xFFFF, voh->type);
|
||||||
astream = fmtctx->streams[i];
|
|
||||||
break;
|
switch ((SceNgs2MasteringParam)(phead->id & 0xFFFF)) {
|
||||||
|
case SceNgs2MasteringParam::SETUP: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2MasteringParam::SET_MATRIX: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2MasteringParam::SET_LFE: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2MasteringParam::SET_LIMITER: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2MasteringParam::SET_GAIN: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2MasteringParam::SET_OUTPUT: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2MasteringParam::SET_PEAK_METER: {
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (astream == nullptr) {
|
int32_t voiceControl_reverb(SceNgs2Handle* voh, const SceNgs2VoiceParamHead* phead) {
|
||||||
LOG_ERR(L"ParseRIFF: no audio stream detected!");
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
return Err::Ngs2::FAIL;
|
LOG_DEBUG(L"voice_reverbid:%u type:%u", phead->id & 0xFFFF, voh->type);
|
||||||
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
wf->info.type = ParseWaveType(astream->codecpar->codec_id);
|
int32_t voiceControl_equalizer(SceNgs2Handle* voh, const SceNgs2VoiceParamHead* phead) {
|
||||||
wf->info.sampleRate = astream->codecpar->sample_rate;
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
wf->info.channelsCount = ParseChanCount(astream->codecpar->ch_layout.nb_channels);
|
LOG_DEBUG(L"voice_equalizer id:%u type:%u", phead->id & 0xFFFF, voh->type);
|
||||||
|
|
||||||
// These are unknown for now
|
|
||||||
wf->loopBeginPos = wf->loopEndPos = 0;
|
|
||||||
wf->samplesCount = 0;
|
|
||||||
wf->offset = 0;
|
|
||||||
wf->size = 0;
|
|
||||||
|
|
||||||
// std::vector<AVPacket>* frames = new std::vector<AVPacket>;
|
|
||||||
|
|
||||||
// AVPacket packet;
|
|
||||||
// while (av_read_frame(fmtctx, &packet) >= 0) {
|
|
||||||
// if (packet.stream_index == astream->index) {
|
|
||||||
// frames->insert(frames->end(), packet);
|
|
||||||
// }
|
|
||||||
// // av_packet_unref(&packet);
|
|
||||||
// }
|
|
||||||
|
|
||||||
wf->numBlocks = 0;
|
|
||||||
wf->block[0].userData = 0;
|
|
||||||
// wf->block[0].userData = (uintptr_t)frames;
|
|
||||||
|
|
||||||
av_free(avioctx);
|
|
||||||
avformat_close_input(&fmtctx);
|
|
||||||
|
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t ProcessWaveData(WaveformInfo* wi, SceNgs2WaveformFormat* wf) {
|
int32_t voiceControl_sampler(SceNgs2Handle* voh, const SceNgs2VoiceParamHead* phead) {
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
LOG_DEBUG(L"voice_sampler id:%u type:%u", phead->id & 0xFFFF, voh->type);
|
||||||
|
|
||||||
switch (wi->type) {
|
if (voh->type != SceNgs2HandleType::Voice) return Err::Ngs2::INVALID_VOICE_HANDLE;
|
||||||
case WAVEFORM_DATA: return ParseData((const uint8_t*)wi->ud.dataPtr, wi->size, wf);
|
|
||||||
|
|
||||||
default: LOG_ERR(L"Unimplemented waveform reader: %d", wi->type);
|
auto voice = (SceNgs2Handle_voice*)voh;
|
||||||
|
|
||||||
|
switch ((SceNgs2SamplerParam)(phead->id & 0xFFFF)) {
|
||||||
|
case SceNgs2SamplerParam::SETUP: {
|
||||||
|
auto item = (SceNgs2SamplerVoiceSetupParam*)phead;
|
||||||
|
voice->info = item->format;
|
||||||
|
} break;
|
||||||
|
case SceNgs2SamplerParam::ADD_WAVEFORM_BLOCKS: {
|
||||||
|
return _voiceControlWaveformBlock(voh, (const SceNgs2SamplerVoiceWaveformBlocksParam*)phead);
|
||||||
|
}
|
||||||
|
case SceNgs2SamplerParam::REPLACE_WAVEFORM_ADDRESS: {
|
||||||
|
auto item = (SceNgs2CustomSamplerVoiceWaveformAddressParam*)phead;
|
||||||
|
if (voice->reader != nullptr) voice->reader->setNewData(item->pDataStart, item->pDataEnd);
|
||||||
|
} break;
|
||||||
|
case SceNgs2SamplerParam::SET_WAVEFORM_FRAME_OFFSET: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2SamplerParam::EXIT_LOOP: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2SamplerParam::SET_PITCH: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2SamplerParam::SET_ENVELOPE: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2SamplerParam::SET_DISTORTION: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2SamplerParam::SET_USER_FX: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2SamplerParam::SET_PEAK_METER: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2SamplerParam::SET_FILTER: {
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* todo: Deal with WAV/VAG files */
|
return Ok;
|
||||||
return Err::Ngs2::INVALID_WAVEFORM_DATA;
|
}
|
||||||
|
|
||||||
|
int32_t voiceControl_submixer(SceNgs2Handle* voh, const SceNgs2VoiceParamHead* phead) {
|
||||||
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
LOG_DEBUG(L"voice_submixer id:%u type:%u", phead->id & 0xFFFF, voh->type);
|
||||||
|
|
||||||
|
switch ((SceNgs2SubmixerParam)(phead->id & 0xFFFF)) {
|
||||||
|
case SceNgs2SubmixerParam::SETUP: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2SubmixerParam::SET_ENVELOPE: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2SubmixerParam::SET_COMPRESSOR: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2SubmixerParam::SET_DISTORTION: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2SubmixerParam::SET_USER_FX: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2SubmixerParam::SET_PEAK_METER: {
|
||||||
|
} break;
|
||||||
|
case SceNgs2SubmixerParam::SET_FILTER: {
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
return Ok;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
SceNgs2Handle_voice::~SceNgs2Handle_voice() {
|
||||||
|
if (reader != nullptr) delete reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceNgs2Handle_voice::ev_KickEvent(SceNgs2VoiceEvent id) {
|
||||||
|
state.bits.Inuse = true;
|
||||||
|
switch (id) {
|
||||||
|
case SceNgs2VoiceEvent::Play: {
|
||||||
|
state.bits.Playing = true;
|
||||||
|
} break;
|
||||||
|
case SceNgs2VoiceEvent::Stop: {
|
||||||
|
state.bits.Stopped = true;
|
||||||
|
state.bits.Playing = false;
|
||||||
|
} break;
|
||||||
|
case SceNgs2VoiceEvent::Stop_imm: {
|
||||||
|
state.bits.Stopped = true;
|
||||||
|
state.bits.Playing = false;
|
||||||
|
} break;
|
||||||
|
case SceNgs2VoiceEvent::Kill: {
|
||||||
|
state.bits.Stopped = true;
|
||||||
|
state.bits.Playing = false;
|
||||||
|
} break;
|
||||||
|
case SceNgs2VoiceEvent::Pause: {
|
||||||
|
state.bits.Paused = true;
|
||||||
|
} break;
|
||||||
|
case SceNgs2VoiceEvent::Resume: {
|
||||||
|
state.bits.Paused = false;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
LOG_DEBUG(L"set state voice:0x%08llx id:%u state:%x", (uint64_t)this, id, state.data);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
EXPORT const char* MODULE_NAME = "libSceNgs2";
|
EXPORT const char* MODULE_NAME = "libSceNgs2";
|
||||||
|
|
||||||
|
// ### Create
|
||||||
|
EXPORT SYSV_ABI int32_t sceNgs2RackQueryBufferSize(uint32_t rackId, const SceNgs2RackOption* ro, SceNgs2ContextBufferInfo* cbi) {
|
||||||
|
if (cbi == nullptr) return Err::Ngs2::INVALID_BUFFER_ADDRESS;
|
||||||
|
if (ro != nullptr && ro->size < sizeof(SceNgs2RackOption)) return Err::Ngs2::INVALID_OPTION_SIZE;
|
||||||
|
|
||||||
|
auto const numVoices = ro != nullptr ? ro->maxVoices : SceNgs2RackOption().maxVoices;
|
||||||
|
cbi->hostBufferSize = sizeof(SceNgs2Handle_rack);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT SYSV_ABI int32_t sceNgs2SystemQueryBufferSize(const SceNgs2SystemOption* sysopt, SceNgs2ContextBufferInfo* cbi) {
|
||||||
|
if (cbi == nullptr) return Err::Ngs2::INVALID_BUFFER_ADDRESS;
|
||||||
|
cbi->hostBufferSize = sizeof(SceNgs2Handle_system);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT SYSV_ABI int32_t sceNgs2SystemCreateWithAllocator(const SceNgs2SystemOption* sysopt, SceNgs2BufferAllocator* alloc, SceNgs2Handle** outh) {
|
||||||
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
|
||||||
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
|
|
||||||
|
if (alloc == nullptr || alloc->allocHandler == nullptr) return Err::Ngs2::INVALID_BUFFER_ALLOCATOR;
|
||||||
|
if (outh == nullptr) return Err::Ngs2::INVALID_OUT_ADDRESS;
|
||||||
|
if (sysopt != nullptr && sysopt->size < sizeof(SceNgs2SystemOption)) return Err::Ngs2::INVALID_OPTION_SIZE;
|
||||||
|
|
||||||
|
SceNgs2ContextBufferInfo cbi = {
|
||||||
|
.hostBuffer = nullptr,
|
||||||
|
.hostBufferSize = sizeof(SceNgs2Handle_system),
|
||||||
|
.userData = alloc->userData,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (auto ret = alloc->allocHandler(&cbi)) {
|
||||||
|
LOG_ERR(L"Ngs2System: Allocation failed!");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outh = new (cbi.hostBuffer) SceNgs2Handle_system(alloc);
|
||||||
|
getPimpl()->handles.emplace(*outh);
|
||||||
|
|
||||||
|
LOG_DEBUG(L"-> System: 0x%08llx", (uint64_t)*outh);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT SYSV_ABI int32_t sceNgs2SystemCreate(const SceNgs2SystemOption* sysopt, const SceNgs2ContextBufferInfo* cbi, SceNgs2Handle** outh) {
|
||||||
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
|
|
||||||
|
if (outh == nullptr) return Err::Ngs2::INVALID_OUT_ADDRESS;
|
||||||
|
if (sysopt != nullptr && sysopt->size < sizeof(SceNgs2SystemOption)) return Err::Ngs2::INVALID_OPTION_SIZE;
|
||||||
|
if (cbi == nullptr || cbi->hostBuffer == nullptr || cbi->hostBufferSize < sizeof(SceNgs2Handle)) return Err::Ngs2::INVALID_BUFFER_ADDRESS;
|
||||||
|
|
||||||
|
*outh = new (cbi->hostBuffer) SceNgs2Handle_system(nullptr);
|
||||||
|
getPimpl()->handles.emplace(*outh);
|
||||||
|
|
||||||
|
LOG_DEBUG(L"-> System: 0x%08llx", (uint64_t)*outh);
|
||||||
|
return (*outh) != nullptr ? Ok : Err::Ngs2::FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT SYSV_ABI int32_t sceNgs2RackCreate(SceNgs2Handle* sysh, uint32_t rackId, const SceNgs2RackOption* ropt, const SceNgs2ContextBufferInfo* cbi,
|
||||||
|
SceNgs2Handle** outh) {
|
||||||
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
|
|
||||||
|
if (outh == nullptr) return Err::Ngs2::INVALID_OUT_ADDRESS;
|
||||||
|
if (sysh == nullptr) return Err::Ngs2::INVALID_SYSTEM_HANDLE;
|
||||||
|
if (ropt != nullptr && ropt->size < sizeof(SceNgs2RackOption)) return Err::Ngs2::INVALID_OPTION_SIZE;
|
||||||
|
if (cbi == nullptr || cbi->hostBuffer == nullptr || cbi->hostBufferSize < sizeof(SceNgs2Handle)) return Err::Ngs2::INVALID_BUFFER_ADDRESS;
|
||||||
|
auto system = (SceNgs2Handle_system*)sysh;
|
||||||
|
|
||||||
|
*outh = new (cbi->hostBuffer) SceNgs2Handle_rack(system, ropt, rackId);
|
||||||
|
getPimpl()->handles.emplace(*outh);
|
||||||
|
|
||||||
|
auto rack = (SceNgs2Handle_rack*)(*outh);
|
||||||
|
|
||||||
|
// Add to system
|
||||||
|
if (rackId == SCE_NGS2_RACK_ID_MASTERING || rackId == SCE_NGS2_RACK_ID_CUSTOM_MASTERING) {
|
||||||
|
system->mastering = rack;
|
||||||
|
} else if (rackId == SCE_NGS2_RACK_ID_SAMPLER || rackId == SCE_NGS2_RACK_ID_CUSTOM_SAMPLER) {
|
||||||
|
system->sampler = rack;
|
||||||
|
} else if (rackId == SCE_NGS2_RACK_ID_SUBMIXER || rackId == SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER) {
|
||||||
|
system->submixer = rack;
|
||||||
|
} else if (rackId == SCE_NGS2_RACK_ID_REVERB) {
|
||||||
|
system->reverb = rack;
|
||||||
|
} else if (rackId == SCE_NGS2_RACK_ID_EQ) {
|
||||||
|
system->equalizer = rack;
|
||||||
|
} else {
|
||||||
|
LOG_ERR(L"-> Rack: undefined rackid %u", rackId);
|
||||||
|
return Err::Ngs2::FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG(L"-> Rack: system:0x%08llx rack:0x%08llx id:0x%x", (uint64_t)sysh, (uint64_t)*outh, rackId);
|
||||||
|
return (*outh) != nullptr ? Ok : Err::Ngs2::FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT SYSV_ABI int32_t sceNgs2RackCreateWithAllocator(SceNgs2Handle* sysh, uint32_t rackId, const SceNgs2RackOption* ro, const SceNgs2BufferAllocator* alloc,
|
||||||
|
SceNgs2Handle** outh) {
|
||||||
|
if (sysh == nullptr) return Err::Ngs2::INVALID_SYSTEM_HANDLE;
|
||||||
|
if (alloc == nullptr) return Err::Ngs2::INVALID_BUFFER_ALLOCATOR;
|
||||||
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
|
|
||||||
|
auto system = (SceNgs2Handle_system*)sysh;
|
||||||
|
|
||||||
|
SceNgs2ContextBufferInfo cbi = {
|
||||||
|
.hostBuffer = nullptr,
|
||||||
|
.hostBufferSize = sizeof(SceNgs2Handle_rack),
|
||||||
|
.userData = alloc->userData,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (auto ret = alloc->allocHandler(&cbi)) {
|
||||||
|
LOG_ERR(L"Ngs2Rack: Allocation failed!");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outh = new (cbi.hostBuffer) SceNgs2Handle_rack(system, ro, rackId);
|
||||||
|
getPimpl()->handles.emplace(*outh);
|
||||||
|
|
||||||
|
auto rack = (SceNgs2Handle_rack*)(*outh);
|
||||||
|
|
||||||
|
// Add to system
|
||||||
|
if (rackId == SCE_NGS2_RACK_ID_MASTERING || rackId == SCE_NGS2_RACK_ID_CUSTOM_MASTERING) {
|
||||||
|
system->mastering = rack;
|
||||||
|
} else if (rackId == SCE_NGS2_RACK_ID_SAMPLER || rackId == SCE_NGS2_RACK_ID_CUSTOM_SAMPLER) {
|
||||||
|
system->sampler = rack;
|
||||||
|
} else if (rackId == SCE_NGS2_RACK_ID_SUBMIXER || rackId == SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER) {
|
||||||
|
system->submixer = rack;
|
||||||
|
} else if (rackId == SCE_NGS2_RACK_ID_REVERB) {
|
||||||
|
system->reverb = rack;
|
||||||
|
} else if (rackId == SCE_NGS2_RACK_ID_EQ) {
|
||||||
|
system->equalizer = rack;
|
||||||
|
} else {
|
||||||
|
LOG_ERR(L"-> Rack: undefined rackid %u", rackId);
|
||||||
|
return Err::Ngs2::FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG(L"-> Rack: system:0x%08llx rack:0x%08llx id:0x%x", (uint64_t)sysh, (uint64_t)*outh, rackId);
|
||||||
|
return (*outh) != nullptr ? Ok : Err::Ngs2::FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- create
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2ReportRegisterHandler(uint32_t type, SceNgs2ReportHandler func, uintptr_t userData, SceNgs2Handle** outh) {
|
EXPORT SYSV_ABI int32_t sceNgs2ReportRegisterHandler(uint32_t type, SceNgs2ReportHandler func, uintptr_t userData, SceNgs2Handle** outh) {
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
LOG_TRACE(L"todo %S", __FUNCTION__);
|
LOG_TRACE(L"todo %S", __FUNCTION__);
|
||||||
@ -197,27 +377,77 @@ EXPORT SYSV_ABI int32_t sceNgs2CustomRackGetModuleInfo(SceNgs2Handle* rh, uint32
|
|||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2ParseWaveformData(const void* ptr, size_t size, SceNgs2WaveformFormat* wf) {
|
// ### WAVE File parsing
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
|
||||||
LOG_TRACE(L"todo %S", __FUNCTION__);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parse the wave (file) data
|
||||||
|
*
|
||||||
|
* @param ptr Game/Application reads (file) and exposes the data pointer
|
||||||
|
* @param size size of data(file)
|
||||||
|
* @param wf
|
||||||
|
* @return result
|
||||||
|
*/
|
||||||
|
EXPORT SYSV_ABI int32_t sceNgs2ParseWaveformData(const void* ptr, size_t size, SceNgs2WaveformFormat* wf) {
|
||||||
if (ptr == nullptr) {
|
if (ptr == nullptr) {
|
||||||
return Err::Ngs2::INVALID_BUFFER_ADDRESS;
|
return Err::Ngs2::INVALID_BUFFER_ADDRESS;
|
||||||
}
|
}
|
||||||
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
|
|
||||||
WaveformInfo wi {
|
userData_inerBuffer userData {ptr, size, 0};
|
||||||
.type = WAVEFORM_DATA,
|
return parseRiffWave(readFunc_linearBuffer, seekFunc_linearBuffer, &userData, wf);
|
||||||
.ud = {.dataPtr = ptr},
|
}
|
||||||
.size = size,
|
|
||||||
|
/**
|
||||||
|
* @brief Parse the wave file
|
||||||
|
*
|
||||||
|
* @param ptr Game/Application reads file and exposes the data pointer
|
||||||
|
* @param offset offset of file
|
||||||
|
* @param wf
|
||||||
|
* @return result
|
||||||
|
*/
|
||||||
|
|
||||||
|
EXPORT SYSV_ABI int32_t sceNgs2ParseWaveformFile(const char* path, long offset, SceNgs2WaveformFormat* wf) {
|
||||||
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
|
|
||||||
|
filesystem::SceOpen const fileFlags {
|
||||||
|
.mode = filesystem::SceOpenMode::RDONLY,
|
||||||
};
|
};
|
||||||
|
|
||||||
return ProcessWaveData(&wi, wf);
|
auto fileHandle = filesystem::open(path, fileFlags, 0);
|
||||||
|
if (fileHandle < 0) return Err::Ngs2::INVALID_WAVEFORM_DATA;
|
||||||
|
|
||||||
|
if (offset != 0) filesystem::lseek(fileHandle, offset, (int)SceWhence::beg);
|
||||||
|
return parseRiffWave(readFunc_file, seekFunc_file, reinterpret_cast<void*>(fileHandle), wf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parse the wave file using the provided function
|
||||||
|
*
|
||||||
|
* @param func Game/Application reads file and exposes the data pointer
|
||||||
|
* @param userData_ offset of file
|
||||||
|
* @param wf
|
||||||
|
* @return result
|
||||||
|
*/
|
||||||
|
|
||||||
|
EXPORT SYSV_ABI int32_t sceNgs2ParseWaveformUser(SceWaveformUserFunc func, uintptr_t userData_, SceNgs2WaveformFormat* wf) {
|
||||||
|
if (func == nullptr) {
|
||||||
|
return Err::Ngs2::INVALID_BUFFER_ADDRESS;
|
||||||
|
}
|
||||||
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
|
|
||||||
|
userData_user userData {func, userData_, 0};
|
||||||
|
return parseRiffWave(readFunc_user, seekFunc_user, (void*)&userData, wf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - wave parsing
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2GetWaveformFrameInfo(const SceNgs2WaveformInfo* fmt, uint32_t* outFrameSize, uint32_t* outNumFrameSamples,
|
EXPORT SYSV_ABI int32_t sceNgs2GetWaveformFrameInfo(const SceNgs2WaveformInfo* fmt, uint32_t* outFrameSize, uint32_t* outNumFrameSamples,
|
||||||
uint32_t* outUnitsPerFrame, uint32_t* outNumDelaySamples) {
|
uint32_t* outUnitsPerFrame, uint32_t* outNumDelaySamples) {
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
LOG_TRACE(L"todo %S", __FUNCTION__);
|
LOG_TRACE(L"todo %S", __FUNCTION__);
|
||||||
|
|
||||||
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
|
|
||||||
if (outFrameSize) *outFrameSize = 1; // Some games crashes with divide by zero exception if we set 0 here
|
if (outFrameSize) *outFrameSize = 1; // Some games crashes with divide by zero exception if we set 0 here
|
||||||
if (outNumFrameSamples) *outNumFrameSamples = 0;
|
if (outNumFrameSamples) *outNumFrameSamples = 0;
|
||||||
if (outUnitsPerFrame) *outUnitsPerFrame = 0;
|
if (outUnitsPerFrame) *outUnitsPerFrame = 0;
|
||||||
@ -238,44 +468,6 @@ EXPORT SYSV_ABI int32_t sceNgs2PanInit() {
|
|||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2ParseWaveformFile(const char* path, long offset, SceNgs2WaveformFormat* wf) {
|
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
|
||||||
LOG_ERR(L"todo %S", __FUNCTION__);
|
|
||||||
|
|
||||||
filesystem::SceOpen flags {
|
|
||||||
.mode = filesystem::SceOpenMode::RDONLY,
|
|
||||||
};
|
|
||||||
|
|
||||||
WaveformInfo wi {
|
|
||||||
.type = WAVEFORM_DATA,
|
|
||||||
.ud = {.fileHandle = filesystem::open(path, flags, {})},
|
|
||||||
.offset = offset,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (wi.ud.fileHandle == 0) {
|
|
||||||
return Err::Ngs2::INVALID_WAVEFORM_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ProcessWaveData(&wi, wf);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2ParseWaveformUser(SceWaveformUserFunc* user, size_t size, SceNgs2WaveformFormat* wf) {
|
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
|
||||||
LOG_ERR(L"todo %S", __FUNCTION__);
|
|
||||||
|
|
||||||
if (user == nullptr) {
|
|
||||||
return Err::Ngs2::INVALID_BUFFER_ADDRESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
WaveformInfo wi {
|
|
||||||
.type = WAVEFORM_USER,
|
|
||||||
.ud = {.userFunc = user},
|
|
||||||
.size = size,
|
|
||||||
};
|
|
||||||
|
|
||||||
return ProcessWaveData(&wi, wf);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2RackGetInfo(SceNgs2Handle* rh, SceNgs2RackInfo* outi, size_t infosz) {
|
EXPORT SYSV_ABI int32_t sceNgs2RackGetInfo(SceNgs2Handle* rh, SceNgs2RackInfo* outi, size_t infosz) {
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
LOG_ERR(L"todo %S", __FUNCTION__);
|
LOG_ERR(L"todo %S", __FUNCTION__);
|
||||||
@ -296,12 +488,18 @@ EXPORT SYSV_ABI int32_t sceNgs2RackGetUserData(SceNgs2Handle* rh, uintptr_t* use
|
|||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2RackGetVoiceHandle(SceNgs2Handle* rh, uint32_t voiceId, SceNgs2Handle** outh) {
|
EXPORT SYSV_ABI int32_t sceNgs2RackGetVoiceHandle(SceNgs2Handle* rh, uint32_t voiceId, SceNgs2Handle** outh) {
|
||||||
if (rh == nullptr) return Err::Ngs2::INVALID_RACK_HANDLE;
|
|
||||||
if (voiceId > rh->un.rack.info.maxVoices) return Err::Ngs2::INVALID_VOICE_INDEX;
|
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
LOG_TRACE(L"todo %S", __FUNCTION__);
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
// todo: write to outh voice handle from rack
|
|
||||||
*outh = &rh->un.rack.voices[voiceId];
|
if (rh == nullptr || rh->type != SceNgs2HandleType::Rack) return Err::Ngs2::INVALID_RACK_HANDLE;
|
||||||
|
|
||||||
|
auto rack = (SceNgs2Handle_rack*)rh;
|
||||||
|
if (voiceId > rack->options.maxVoices) return Err::Ngs2::INVALID_VOICE_INDEX;
|
||||||
|
|
||||||
|
*outh = &rack->voices.emplace(std::make_pair(voiceId, rack)).first->second;
|
||||||
|
|
||||||
|
getPimpl()->handles.emplace(*outh);
|
||||||
|
LOG_DEBUG(L"-> GetVoiceHandle: rack:0x%08llx id:%u @0x%08llx", (uint64_t)rh, voiceId, (uint64_t)*outh);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,22 +557,36 @@ EXPORT SYSV_ABI int32_t sceNgs2SystemUnlock(SceNgs2Handle* sysh) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2SystemRender(SceNgs2Handle* sysh, SceNgs2RenderBufferInfo* rbi, int32_t count) {
|
EXPORT SYSV_ABI int32_t sceNgs2SystemRender(SceNgs2Handle* sysh, SceNgs2RenderBufferInfo* rbi, int32_t count) {
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
LOG_TRACE(L"todo %S", __FUNCTION__);
|
auto system = (SceNgs2Handle_system*)sysh;
|
||||||
if (sysh == nullptr) return Err::Ngs2::INVALID_SYSTEM_HANDLE;
|
if (system == nullptr) return Err::Ngs2::INVALID_SYSTEM_HANDLE;
|
||||||
if (rbi->bufferPtr == nullptr) return Err::Ngs2::INVALID_BUFFER_ADDRESS;
|
if (rbi->bufferPtr == nullptr) return Err::Ngs2::INVALID_BUFFER_ADDRESS;
|
||||||
if (rbi->bufferSize == 0) return Err::Ngs2::INVALID_BUFFER_SIZE;
|
if (rbi->bufferSize == 0) return Err::Ngs2::INVALID_BUFFER_SIZE;
|
||||||
if (rbi->waveType >= SceNgs2WaveFormType::MAX_TYPES) return Err::Ngs2::INVALID_WAVEFORM_TYPE;
|
if (rbi->waveType >= SceNgs2WaveFormType::MAX_TYPES) return Err::Ngs2::INVALID_WAVEFORM_TYPE;
|
||||||
if (rbi->channelsCount > SceNgs2ChannelsCount::CH_7_1) return Err::Ngs2::INVALID_NUM_CHANNELS;
|
if (rbi->channelsCount > SceNgs2ChannelsCount::CH_7_1) return Err::Ngs2::INVALID_NUM_CHANNELS;
|
||||||
|
|
||||||
|
uint32_t const numSamples = rbi->bufferSize / ((uint32_t)rbi->channelsCount * getSampleBytes(rbi->waveType));
|
||||||
|
|
||||||
|
if (system->sampler == nullptr) {
|
||||||
|
//
|
||||||
for (int32_t i = 0; i < count; i++) {
|
for (int32_t i = 0; i < count; i++) {
|
||||||
if (rbi[i].bufferPtr != nullptr) {
|
if (rbi[i].bufferPtr != nullptr) {
|
||||||
std::memset(rbi[i].bufferPtr, 0, rbi[i].bufferSize);
|
std::memset(rbi[i].bufferPtr, 0, rbi[i].bufferSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: ffmpeg should convert all the wave data to `rbi->waveType`
|
} else {
|
||||||
|
for (int32_t i = 0; i < count; i++) {
|
||||||
|
if (rbi[i].bufferPtr != nullptr) {
|
||||||
|
std::memset(rbi[i].bufferPtr, 0, rbi[i].bufferSize);
|
||||||
|
for (auto& voice: system->sampler->voices) {
|
||||||
|
if (voice.second.reader != nullptr) {
|
||||||
|
// voice.second.reader->getAudio(&rbi[i], numSamples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,36 +620,80 @@ EXPORT SYSV_ABI int32_t sceNgs2VoiceGetPortInfo(SceNgs2Handle** vh, uint32_t por
|
|||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t _voiceControlWaveformBlock(SceNgs2Handle* voh, const SceNgs2SamplerVoiceWaveformBlocksParam* svwfbp) {
|
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
|
||||||
LOG_TRACE(L"waveblock: %d\n", svwfbp->numBlocks);
|
|
||||||
if (svwfbp->aBlock) LOG_TRACE(L"waveptr: %llx\n", svwfbp->aBlock[0].userData);
|
|
||||||
return Ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2VoiceControl(SceNgs2Handle* voh, const SceNgs2VoiceParamHead* phead) {
|
EXPORT SYSV_ABI int32_t sceNgs2VoiceControl(SceNgs2Handle* voh, const SceNgs2VoiceParamHead* phead) {
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
LOG_TRACE(L"todo %S", __FUNCTION__);
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
switch (phead->id) {
|
|
||||||
case SCE_NGS2_SAMPLER_VOICE_ADD_WAVEFORM_BLOCKS: return _voiceControlWaveformBlock(voh, (const SceNgs2SamplerVoiceWaveformBlocksParam*)phead);
|
|
||||||
|
|
||||||
case (uint32_t)SceNgs2VoiceParam::SET_PORT_VOLUME: break;
|
if (voh == nullptr) return getErr(ErrCode::_EINVAL);
|
||||||
|
uint16_t const rackId_ = phead->id >> 16;
|
||||||
|
|
||||||
default: LOG_TRACE(L"Unhandled voice control command: (%p, %08x)", voh, phead->id);
|
auto curItem = phead;
|
||||||
|
int32_t ret = Ok;
|
||||||
|
while (true) {
|
||||||
|
uint16_t const rackId = curItem->id >> 16;
|
||||||
|
|
||||||
|
if (rackId == SCE_NGS2_RACK_ID_VOICE)
|
||||||
|
ret = voiceControl_voice(voh, curItem);
|
||||||
|
else if (rackId == SCE_NGS2_RACK_ID_MASTERING || rackId == SCE_NGS2_RACK_ID_CUSTOM_MASTERING)
|
||||||
|
ret = voiceControl_mastering(voh, curItem);
|
||||||
|
else if (rackId == SCE_NGS2_RACK_ID_SAMPLER || rackId == SCE_NGS2_RACK_ID_CUSTOM_SAMPLER)
|
||||||
|
ret = voiceControl_sampler(voh, curItem);
|
||||||
|
else if (rackId == SCE_NGS2_RACK_ID_SUBMIXER || rackId == SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER)
|
||||||
|
ret = voiceControl_submixer(voh, curItem);
|
||||||
|
else if (rackId == SCE_NGS2_RACK_ID_REVERB)
|
||||||
|
ret = voiceControl_reverb(voh, curItem);
|
||||||
|
else if (rackId == SCE_NGS2_RACK_ID_EQ)
|
||||||
|
ret = voiceControl_equalizer(voh, curItem);
|
||||||
|
else
|
||||||
|
LOG_ERR(L"Unhandled rackId: %08x", rackId);
|
||||||
|
|
||||||
|
if (curItem->next == 0 || ret != Ok) break;
|
||||||
|
|
||||||
|
curItem = (SceNgs2VoiceParamHead*)((uint64_t)curItem + curItem->next);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2VoiceGetState(SceNgs2Handle* voh, SceNgs2VoiceState* state, size_t size) {
|
EXPORT SYSV_ABI int32_t sceNgs2VoiceGetState(SceNgs2Handle* voh, SceNgs2VoiceState* state, size_t size) {
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
LOG_TRACE(L"todo %S", __FUNCTION__);
|
|
||||||
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
|
|
||||||
|
if (voh == nullptr || state == nullptr) return getErr(ErrCode::_EINVAL);
|
||||||
|
|
||||||
|
auto pimpl = getPimpl();
|
||||||
|
if (auto it = pimpl->handles.find(voh); it == pimpl->handles.end()) return Err::Ngs2::INVALID_VOICE_HANDLE;
|
||||||
|
if (voh->type != SceNgs2HandleType::Voice) return Err::Ngs2::INVALID_VOICE_HANDLE;
|
||||||
|
|
||||||
|
auto voice = (SceNgs2Handle_voice*)voh;
|
||||||
|
if (voice->reader != nullptr) {
|
||||||
|
if (size != sizeof(SceNgs2SamplerVoiceState)) return getErr(ErrCode::_EINVAL);
|
||||||
|
|
||||||
|
voice->reader->getState((SceNgs2SamplerVoiceState*)state);
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->stateFlags = voice->state.data;
|
||||||
|
|
||||||
|
// LOG_DEBUG(L"state voice:0x%08llx state:%x", (uint64_t)voh, state->stateFlags);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2VoiceGetStateFlags(SceNgs2Handle* voh, uint32_t* flags) {
|
EXPORT SYSV_ABI int32_t sceNgs2VoiceGetStateFlags(SceNgs2Handle* voh, uint32_t* flags) {
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
LOG_TRACE(L"todo %S", __FUNCTION__);
|
|
||||||
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
|
if (voh == nullptr || flags == nullptr) return getErr(ErrCode::_EINVAL);
|
||||||
|
|
||||||
|
auto pimpl = getPimpl();
|
||||||
|
if (auto it = pimpl->handles.find(voh); it == pimpl->handles.end()) return Err::Ngs2::INVALID_VOICE_HANDLE;
|
||||||
|
if (voh->type != SceNgs2HandleType::Voice) return Err::Ngs2::INVALID_VOICE_HANDLE;
|
||||||
|
|
||||||
|
auto voice = (SceNgs2Handle_voice*)voh;
|
||||||
|
*flags = voice->state.data;
|
||||||
|
|
||||||
|
// LOG_DEBUG(L"state voice:0x%08llx state:%x", (uint64_t)voh, *flags);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,7 +705,7 @@ EXPORT SYSV_ABI int32_t sceNgs2GeomApply() {
|
|||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2GeomCalcListener() {
|
EXPORT SYSV_ABI int32_t sceNgs2GeomCalcListener() {
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
LOG_ERR(L"todo %S", __FUNCTION__);
|
LOG_TRACE(L"todo %S", __FUNCTION__);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,158 +721,54 @@ EXPORT SYSV_ABI int32_t sceNgs2GeomResetSourceParam(SceNgs2GeomSourceParam* para
|
|||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2RackCreate(SceNgs2Handle* sysh, uint32_t rackId, const SceNgs2RackOption* ropt, const SceNgs2ContextBufferInfo* cbi,
|
|
||||||
SceNgs2Handle** outh) {
|
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
|
||||||
LOG_ERR(L"todo %S(%p, %d, %p, %p, %p)", __FUNCTION__, sysh, rackId, ropt, cbi, outh);
|
|
||||||
if (outh == nullptr) return Err::Ngs2::INVALID_OUT_ADDRESS;
|
|
||||||
if (sysh == nullptr) return Err::Ngs2::INVALID_SYSTEM_HANDLE;
|
|
||||||
if (ropt != nullptr && ropt->size < sizeof(SceNgs2RackOption)) return Err::Ngs2::INVALID_OPTION_SIZE;
|
|
||||||
if (cbi == nullptr || cbi->hostBuffer == nullptr || cbi->hostBufferSize < sizeof(SceNgs2Handle)) return Err::Ngs2::INVALID_BUFFER_ADDRESS;
|
|
||||||
|
|
||||||
*outh = (SceNgs2Handle*)cbi->hostBuffer;
|
|
||||||
(*outh)->allocSet = false;
|
|
||||||
(*outh)->alloc.allocHandler = nullptr;
|
|
||||||
(*outh)->alloc.freeHandler = nullptr;
|
|
||||||
(*outh)->alloc.userData = nullptr;
|
|
||||||
(*outh)->owner = sysh;
|
|
||||||
|
|
||||||
if (ropt != nullptr) {
|
|
||||||
(*outh)->un.rack.info.maxPorts = ropt->maxPorts;
|
|
||||||
(*outh)->un.rack.info.maxMatrices = ropt->maxMatrices;
|
|
||||||
(*outh)->un.rack.info.maxGrainSamples = ropt->maxGrainSamples;
|
|
||||||
(*outh)->un.rack.info.maxVoices = ropt->maxVoices;
|
|
||||||
} else {
|
|
||||||
(*outh)->un.rack.info.maxPorts = 1;
|
|
||||||
(*outh)->un.rack.info.maxMatrices = 1;
|
|
||||||
(*outh)->un.rack.info.maxGrainSamples = 1;
|
|
||||||
(*outh)->un.rack.info.maxVoices = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto vo = (*outh)->un.rack.voices = new SceNgs2Handle;
|
|
||||||
vo->allocSet = false;
|
|
||||||
vo->alloc.allocHandler = nullptr;
|
|
||||||
vo->alloc.freeHandler = nullptr;
|
|
||||||
vo->alloc.userData = nullptr;
|
|
||||||
|
|
||||||
return (*outh) != nullptr ? Ok : Err::Ngs2::FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2RackCreateWithAllocator(SceNgs2Handle* sysh, uint32_t rackId, const SceNgs2RackOption* ro, const SceNgs2BufferAllocator* alloc,
|
|
||||||
SceNgs2Handle** outh) {
|
|
||||||
if (sysh == nullptr) return Err::Ngs2::INVALID_SYSTEM_HANDLE;
|
|
||||||
if (alloc == nullptr) return Err::Ngs2::INVALID_BUFFER_ALLOCATOR;
|
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
|
||||||
LOG_TRACE(L"todo %S", __FUNCTION__);
|
|
||||||
|
|
||||||
SceNgs2ContextBufferInfo cbi = {
|
|
||||||
.hostBuffer = nullptr,
|
|
||||||
.hostBufferSize = sizeof(SceNgs2Handle),
|
|
||||||
.userData = alloc->userData,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (auto ret = alloc->allocHandler(&cbi)) {
|
|
||||||
LOG_ERR(L"Ngs2Rack: Allocation failed!");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
*outh = (SceNgs2Handle*)cbi.hostBuffer;
|
|
||||||
(*outh)->owner = sysh;
|
|
||||||
(*outh)->allocSet = true;
|
|
||||||
(*outh)->alloc = *alloc;
|
|
||||||
(*outh)->cbi = cbi;
|
|
||||||
|
|
||||||
cbi.hostBufferSize = sizeof(SceNgs2Handle) * ((ro != nullptr) ? ro->maxVoices : 1);
|
|
||||||
|
|
||||||
if (auto ret = alloc->allocHandler(&cbi)) {
|
|
||||||
LOG_ERR(L"Ngs2Rack: Voice allocation failed");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto vo = (*outh)->un.rack.voices = (SceNgs2Handle*)cbi.hostBuffer;
|
|
||||||
vo->allocSet = true;
|
|
||||||
vo->alloc = *alloc;
|
|
||||||
|
|
||||||
return Ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2RackDestroy(SceNgs2Handle* rh, SceNgs2ContextBufferInfo* cbi) {
|
EXPORT SYSV_ABI int32_t sceNgs2RackDestroy(SceNgs2Handle* rh, SceNgs2ContextBufferInfo* cbi) {
|
||||||
if (rh == nullptr) return Err::Ngs2::INVALID_SYSTEM_HANDLE;
|
if (rh == nullptr) return Err::Ngs2::INVALID_RACK_HANDLE;
|
||||||
if (rh->allocSet) {
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
cbi->hostBufferSize = sizeof(SceNgs2Handle);
|
|
||||||
cbi->hostBuffer = rh->un.rack.voices;
|
auto rack = (SceNgs2Handle_rack*)rh;
|
||||||
if (auto ret = rh->alloc.freeHandler(cbi)) return ret;
|
|
||||||
cbi->hostBuffer = rh;
|
auto freeHandler = rack->parent->alloc.freeHandler;
|
||||||
if (auto ret = rh->alloc.freeHandler(cbi)) return ret;
|
|
||||||
} else {
|
int32_t ret = Ok;
|
||||||
if (rh->un.rack.voices != nullptr) delete rh->un.rack.voices;
|
|
||||||
|
for (auto voice: rack->voices) {
|
||||||
|
getPimpl()->handles.erase(&voice.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok;
|
getPimpl()->handles.erase(rh);
|
||||||
}
|
if (freeHandler != nullptr) {
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2RackQueryBufferSize(uint32_t rackId, const SceNgs2RackOption* ro, SceNgs2ContextBufferInfo* cbi) {
|
|
||||||
cbi->hostBufferSize = sizeof(SceNgs2Handle);
|
|
||||||
return Ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2SystemCreateWithAllocator(const SceNgs2SystemOption* sysopt, SceNgs2BufferAllocator* alloc, SceNgs2Handle** outh) {
|
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
|
||||||
LOG_ERR(L"todo %S(%p, %p, %p)", __FUNCTION__, sysopt, alloc, outh);
|
|
||||||
if (alloc == nullptr || alloc->allocHandler == nullptr) return Err::Ngs2::INVALID_BUFFER_ALLOCATOR;
|
|
||||||
if (outh == nullptr) return Err::Ngs2::INVALID_OUT_ADDRESS;
|
|
||||||
if (sysopt != nullptr && sysopt->size < sizeof(SceNgs2SystemOption)) return Err::Ngs2::INVALID_OPTION_SIZE;
|
|
||||||
|
|
||||||
SceNgs2ContextBufferInfo cbi = {
|
SceNgs2ContextBufferInfo cbi = {
|
||||||
.hostBuffer = nullptr,
|
.hostBuffer = rack,
|
||||||
.hostBufferSize = sizeof(SceNgs2Handle),
|
.hostBufferSize = sizeof(SceNgs2Handle_rack),
|
||||||
.userData = alloc->userData,
|
|
||||||
};
|
};
|
||||||
|
rack->~SceNgs2Handle_rack();
|
||||||
|
ret = freeHandler(&cbi);
|
||||||
|
} else
|
||||||
|
rack->~SceNgs2Handle_rack();
|
||||||
|
|
||||||
if (auto ret = alloc->allocHandler(&cbi)) {
|
|
||||||
LOG_ERR(L"Ngs2System: Allocation failed!");
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
*outh = (SceNgs2Handle*)cbi.hostBuffer;
|
|
||||||
(*outh)->owner = nullptr;
|
|
||||||
(*outh)->allocSet = true;
|
|
||||||
(*outh)->alloc = *alloc;
|
|
||||||
(*outh)->cbi = cbi;
|
|
||||||
|
|
||||||
return Ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2SystemCreate(const SceNgs2SystemOption* sysopt, const SceNgs2ContextBufferInfo* cbi, SceNgs2Handle** outh) {
|
|
||||||
LOG_USE_MODULE(libSceNgs2);
|
|
||||||
LOG_ERR(L"todo %S(%p, %p, %p)", __FUNCTION__, sysopt, cbi, outh);
|
|
||||||
if (outh == nullptr) return Err::Ngs2::INVALID_OUT_ADDRESS;
|
|
||||||
if (sysopt != nullptr && sysopt->size < sizeof(SceNgs2SystemOption)) return Err::Ngs2::INVALID_OPTION_SIZE;
|
|
||||||
if (cbi == nullptr || cbi->hostBuffer == nullptr || cbi->hostBufferSize < sizeof(SceNgs2Handle)) return Err::Ngs2::INVALID_BUFFER_ADDRESS;
|
|
||||||
|
|
||||||
*outh = (SceNgs2Handle*)cbi->hostBuffer;
|
|
||||||
(*outh)->allocSet = false;
|
|
||||||
(*outh)->owner = nullptr;
|
|
||||||
|
|
||||||
return (*outh) != nullptr ? Ok : Err::Ngs2::FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2SystemDestroy(SceNgs2Handle* sysh, SceNgs2ContextBufferInfo* cbi) {
|
EXPORT SYSV_ABI int32_t sceNgs2SystemDestroy(SceNgs2Handle* sysh, SceNgs2ContextBufferInfo* cbi) {
|
||||||
if (sysh == nullptr) return Err::Ngs2::INVALID_SYSTEM_HANDLE;
|
if (sysh == nullptr) return Err::Ngs2::INVALID_SYSTEM_HANDLE;
|
||||||
if (sysh->allocSet) {
|
boost::unique_lock lock(MUTEX_INT);
|
||||||
cbi->hostBuffer = sysh;
|
|
||||||
cbi->hostBufferSize = sizeof(SceNgs2Handle);
|
|
||||||
if (auto ret = sysh->alloc.freeHandler(cbi)) return ret;
|
|
||||||
} else {
|
|
||||||
delete sysh;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok;
|
auto system = (SceNgs2Handle_system*)sysh;
|
||||||
}
|
getPimpl()->handles.erase(system);
|
||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNgs2SystemQueryBufferSize(const SceNgs2SystemOption* sysopt, SceNgs2ContextBufferInfo* cbi) {
|
auto freeHandler = system->alloc.freeHandler;
|
||||||
if (cbi == nullptr) return Err::Ngs2::INVALID_BUFFER_ADDRESS;
|
|
||||||
cbi->hostBufferSize = sizeof(SceNgs2Handle);
|
int32_t ret = Ok;
|
||||||
return Ok;
|
if (freeHandler != nullptr) {
|
||||||
|
SceNgs2ContextBufferInfo cbi = {
|
||||||
|
.hostBuffer = system,
|
||||||
|
.hostBufferSize = sizeof(SceNgs2Handle_system),
|
||||||
|
};
|
||||||
|
system->~SceNgs2Handle_system();
|
||||||
|
ret = freeHandler(&cbi);
|
||||||
|
} else
|
||||||
|
system->~SceNgs2Handle_system();
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
225
modules/libSceNgs2/readFuncs.cpp
Normal file
225
modules/libSceNgs2/readFuncs.cpp
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
#include "readFuncs.h"
|
||||||
|
|
||||||
|
#include "core/fileManager/ifile.h"
|
||||||
|
#include "core/kernel/filesystem.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "riffTypes.h"
|
||||||
|
extern "C" {
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
}
|
||||||
|
#include <functional>
|
||||||
|
#include <list>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
LOG_DEFINE_MODULE(libSceNgs2);
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
static SceNgs2ChannelsCount convChanCount(int num) {
|
||||||
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
|
||||||
|
switch (num) {
|
||||||
|
case 1: return SceNgs2ChannelsCount::CH_1_0;
|
||||||
|
|
||||||
|
case 2: return SceNgs2ChannelsCount::CH_2_0;
|
||||||
|
|
||||||
|
case 6: return SceNgs2ChannelsCount::CH_5_1;
|
||||||
|
|
||||||
|
case 8: return SceNgs2ChannelsCount::CH_7_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_CRIT(L"Invalid channels count sent to ParseChanCount!");
|
||||||
|
return SceNgs2ChannelsCount::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SceNgs2WaveFormType convWaveType(AVCodecID codec) {
|
||||||
|
switch (codec) {
|
||||||
|
case AVCodecID::AV_CODEC_ID_PCM_S8: return SceNgs2WaveFormType::PCM_I8;
|
||||||
|
|
||||||
|
case AVCodecID::AV_CODEC_ID_PCM_U8: return SceNgs2WaveFormType::PCM_U8;
|
||||||
|
|
||||||
|
case AVCodecID::AV_CODEC_ID_ATRAC9: return SceNgs2WaveFormType::ATRAC9;
|
||||||
|
|
||||||
|
default: return SceNgs2WaveFormType::NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int readFunc_linearBuffer(void* userData_, uint8_t* buf, int size) {
|
||||||
|
auto rb = (userData_inerBuffer*)userData_;
|
||||||
|
|
||||||
|
auto len = std::min(int(rb->size - rb->curOffset), size);
|
||||||
|
if (len == 0) return AVERROR_EOF;
|
||||||
|
::memcpy(buf, (uint8_t*)rb->ptr + rb->curOffset, len);
|
||||||
|
rb->curOffset += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t seekFunc_linearBuffer(void* userData_, int64_t pos, int whence) {
|
||||||
|
auto rb = (userData_inerBuffer*)userData_;
|
||||||
|
|
||||||
|
if (whence == AVSEEK_SIZE) return rb->size;
|
||||||
|
|
||||||
|
if (whence == SEEK_SET) {
|
||||||
|
rb->curOffset = pos;
|
||||||
|
} else if (whence == SEEK_CUR) {
|
||||||
|
rb->curOffset += pos;
|
||||||
|
} else if (whence == SEEK_END) {
|
||||||
|
rb->curOffset = rb->size - pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rb->curOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int readFunc_file(void* userData_, uint8_t* buf, int size) {
|
||||||
|
auto handle = (int&)userData_;
|
||||||
|
return filesystem::read(handle, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t seekFunc_file(void* userData_, int64_t offset, int whence) {
|
||||||
|
auto handle = (int&)userData_;
|
||||||
|
return filesystem::lseek(handle, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
int readFunc_user(void* userData_, uint8_t* buf, int size) {
|
||||||
|
auto userData = (userData_user*)userData_;
|
||||||
|
|
||||||
|
auto read = userData->func(userData->userData, userData->curOffset, buf, size);
|
||||||
|
userData->curOffset += read;
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t seekFunc_user(void* userData_, int64_t offset, int whence) {
|
||||||
|
auto userData = (userData_user*)userData_;
|
||||||
|
|
||||||
|
return 0; // undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t parseRiffWave(funcReadBuf_t readFunc, funcSeekBuf_t seekFunc, void* userData, SceNgs2WaveformFormat* wf) {
|
||||||
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
|
||||||
|
// Load headers and check magic
|
||||||
|
// todo use ffmeg, get the correct type (pcm, at9...)
|
||||||
|
|
||||||
|
// Check if correct file
|
||||||
|
RiffWaveHeader riffHeader;
|
||||||
|
readFunc(userData, (uint8_t*)&riffHeader, sizeof(RiffWaveHeader));
|
||||||
|
if (memcmp(riffHeader.chunkID, "RIFF", 4) != 0 || memcmp(riffHeader.riffType, "WAVE", 4) != 0) {
|
||||||
|
LOG_ERR(L"wrong riff 0x%lx 0x%lx", riffHeader.chunkID, riffHeader.riffType);
|
||||||
|
return Err::Ngs2::FAIL;
|
||||||
|
}
|
||||||
|
// -
|
||||||
|
|
||||||
|
// Format header
|
||||||
|
RiffFormatHeader formatHeader;
|
||||||
|
readFunc(userData, (uint8_t*)&formatHeader, sizeof(RiffFormatHeader));
|
||||||
|
|
||||||
|
if (memcmp(formatHeader.chunkID, "fmt ", 4) != 0) {
|
||||||
|
return Err::Ngs2::FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((8 + formatHeader.chunkSize) > sizeof(RiffFormatHeader)) {
|
||||||
|
std::vector<uint8_t> extraFmt(8 + formatHeader.chunkSize - sizeof(RiffFormatHeader));
|
||||||
|
readFunc(userData, extraFmt.data(), extraFmt.size());
|
||||||
|
}
|
||||||
|
// -
|
||||||
|
|
||||||
|
// parse rest
|
||||||
|
uint32_t offset = sizeof(RiffWaveHeader) + 8 + formatHeader.chunkSize;
|
||||||
|
|
||||||
|
uint32_t dataSize = 0;
|
||||||
|
uint32_t numOfSamples = 1;
|
||||||
|
|
||||||
|
// Data header
|
||||||
|
while (offset < riffHeader.chunkSize) {
|
||||||
|
RiffHeader header;
|
||||||
|
readFunc(userData, (uint8_t*)&header, sizeof(RiffHeader));
|
||||||
|
|
||||||
|
auto readBytes = sizeof(RiffHeader);
|
||||||
|
if (memcmp(header.chunkID, "fact", 4) == 0) {
|
||||||
|
readFunc(userData, (uint8_t*)&numOfSamples, 4);
|
||||||
|
readBytes += 4;
|
||||||
|
} else if (memcmp(header.chunkID, "data", 4) == 0) {
|
||||||
|
dataSize = header.chunkSize;
|
||||||
|
break;
|
||||||
|
} // Dump read data
|
||||||
|
|
||||||
|
if ((8 + header.chunkSize) > readBytes) {
|
||||||
|
std::vector<uint8_t> extra(8 + header.chunkSize - readBytes);
|
||||||
|
readFunc(userData, extra.data(), extra.size());
|
||||||
|
}
|
||||||
|
// -
|
||||||
|
|
||||||
|
offset += 8 + header.chunkSize;
|
||||||
|
}
|
||||||
|
if (dataSize == 0) return Err::Ngs2::FAIL;
|
||||||
|
|
||||||
|
// Fill data
|
||||||
|
wf->info.type = (SceNgs2WaveFormType)formatHeader.audioFormat;
|
||||||
|
wf->info.channelsCount = (SceNgs2ChannelsCount)formatHeader.numChannels;
|
||||||
|
wf->info.sampleRate = formatHeader.sampleRate;
|
||||||
|
wf->info.frameOffset = formatHeader.frameSize;
|
||||||
|
wf->info.frameMargin = 0; // todo
|
||||||
|
|
||||||
|
wf->offset = offset;
|
||||||
|
wf->size = dataSize;
|
||||||
|
wf->loopBeginPos = 0; // todo
|
||||||
|
wf->loopEndPos = 0; // todo
|
||||||
|
wf->samplesCount = 1; // todo
|
||||||
|
wf->dataPerFrame = 1; // todo
|
||||||
|
wf->frameSize = formatHeader.frameSize; // todo
|
||||||
|
wf->numframeSamples = 1; // todo
|
||||||
|
wf->samplesDelay = 0; // todo
|
||||||
|
|
||||||
|
auto& block = wf->block[0];
|
||||||
|
block.offset = wf->offset;
|
||||||
|
block.size = dataSize;
|
||||||
|
block.numRepeat = 1;
|
||||||
|
block.skipSamples = 1;
|
||||||
|
block.numSamples = numOfSamples;
|
||||||
|
wf->numBlocks = 1;
|
||||||
|
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVChannelLayout convChannelLayout(SceNgs2ChannelsCount count) {
|
||||||
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
switch (count) {
|
||||||
|
case SceNgs2ChannelsCount::CH_1_0: {
|
||||||
|
return AV_CHANNEL_LAYOUT_MONO;
|
||||||
|
} break;
|
||||||
|
case SceNgs2ChannelsCount::CH_2_0: {
|
||||||
|
return AV_CHANNEL_LAYOUT_STEREO;
|
||||||
|
} break;
|
||||||
|
case SceNgs2ChannelsCount::CH_5_1: {
|
||||||
|
return AV_CHANNEL_LAYOUT_5POINT1;
|
||||||
|
} break;
|
||||||
|
case SceNgs2ChannelsCount::CH_7_1: {
|
||||||
|
return AV_CHANNEL_LAYOUT_CUBE;
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
LOG_ERR(L"channel layout not set");
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
return AV_CHANNEL_LAYOUT_MASK(1, AV_CHANNEL_ORDER_UNSPEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getSampleBytes(SceNgs2WaveFormType type) {
|
||||||
|
switch (type) {
|
||||||
|
case SceNgs2WaveFormType::PCM_U8: return 1;
|
||||||
|
case SceNgs2WaveFormType::PCM_I16LITTLE: return 2;
|
||||||
|
case SceNgs2WaveFormType::PCM_I16BIG: return 2;
|
||||||
|
case SceNgs2WaveFormType::PCM_I24LITTLE: return 3;
|
||||||
|
case SceNgs2WaveFormType::PCM_I24BIG: return 3;
|
||||||
|
case SceNgs2WaveFormType::PCM_I32LITTLE: return 4;
|
||||||
|
case SceNgs2WaveFormType::PCM_I32BIG: return 4;
|
||||||
|
case SceNgs2WaveFormType::PCM_F32LITTLE: return 4;
|
||||||
|
case SceNgs2WaveFormType::PCM_F32BIG: return 4;
|
||||||
|
case SceNgs2WaveFormType::PCM_F64LITTLE: return 8;
|
||||||
|
case SceNgs2WaveFormType::PCM_F64BIG: return 8;
|
||||||
|
case SceNgs2WaveFormType::VAG: return 4;
|
||||||
|
case SceNgs2WaveFormType::ATRAC9: return 4;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return 2;
|
||||||
|
}
|
30
modules/libSceNgs2/readFuncs.h
Normal file
30
modules/libSceNgs2/readFuncs.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
using funcReadBuf_t = int (*)(void*, uint8_t*, int);
|
||||||
|
using funcSeekBuf_t = int64_t (*)(void*, int64_t, int);
|
||||||
|
|
||||||
|
struct userData_user {
|
||||||
|
SceWaveformUserFunc func;
|
||||||
|
uintptr_t userData;
|
||||||
|
size_t curOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct userData_inerBuffer {
|
||||||
|
const void* ptr;
|
||||||
|
size_t size;
|
||||||
|
size_t curOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
int readFunc_linearBuffer(void* userData_, uint8_t* buf, int size);
|
||||||
|
int64_t seekFunc_linearBuffer(void* userData_, int64_t offset, int whence);
|
||||||
|
int readFunc_file(void* userData_, uint8_t* buf, int size);
|
||||||
|
int64_t seekFunc_file(void* userData_, int64_t offset, int whence);
|
||||||
|
int readFunc_user(void* userData_, uint8_t* buf, int size);
|
||||||
|
int64_t seekFunc_user(void* userData_, int64_t offset, int whence);
|
||||||
|
|
||||||
|
int32_t parseRiffWave(funcReadBuf_t readFunc, funcSeekBuf_t seekFunc, void* userData, SceNgs2WaveformFormat* wf);
|
||||||
|
|
||||||
|
struct AVChannelLayout;
|
||||||
|
AVChannelLayout convChannelLayout(SceNgs2ChannelsCount);
|
||||||
|
uint32_t getSampleBytes(SceNgs2WaveFormType);
|
437
modules/libSceNgs2/reader.cpp
Normal file
437
modules/libSceNgs2/reader.cpp
Normal file
@ -0,0 +1,437 @@
|
|||||||
|
#include "reader.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libswresample/swresample.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "logging.h"
|
||||||
|
#include "readFuncs.h"
|
||||||
|
#include "riffTypes.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
LOG_DEFINE_MODULE(libSceNgs2);
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::pair<AVSampleFormat, uint8_t> convFormat(SceNgs2WaveFormType type) {
|
||||||
|
switch (type) {
|
||||||
|
case SceNgs2WaveFormType::PCM_U8: return {AVSampleFormat::AV_SAMPLE_FMT_U8, 1};
|
||||||
|
case SceNgs2WaveFormType::PCM_I16LITTLE: return {AVSampleFormat::AV_SAMPLE_FMT_S16, 2};
|
||||||
|
case SceNgs2WaveFormType::PCM_I16BIG: return {AVSampleFormat::AV_SAMPLE_FMT_S16, 2};
|
||||||
|
case SceNgs2WaveFormType::PCM_I24LITTLE: return {AVSampleFormat::AV_SAMPLE_FMT_NONE, 3};
|
||||||
|
case SceNgs2WaveFormType::PCM_I24BIG: return {AVSampleFormat::AV_SAMPLE_FMT_NONE, 3};
|
||||||
|
case SceNgs2WaveFormType::PCM_I32LITTLE: return {AVSampleFormat::AV_SAMPLE_FMT_S32, 4};
|
||||||
|
case SceNgs2WaveFormType::PCM_I32BIG: return {AVSampleFormat::AV_SAMPLE_FMT_S32, 4};
|
||||||
|
case SceNgs2WaveFormType::PCM_F32LITTLE: return {AVSampleFormat::AV_SAMPLE_FMT_FLT, 4};
|
||||||
|
case SceNgs2WaveFormType::PCM_F32BIG: return {AVSampleFormat::AV_SAMPLE_FMT_FLT, 4};
|
||||||
|
case SceNgs2WaveFormType::PCM_F64LITTLE: return {AVSampleFormat::AV_SAMPLE_FMT_DBL, 8};
|
||||||
|
case SceNgs2WaveFormType::PCM_F64BIG: return {AVSampleFormat::AV_SAMPLE_FMT_DBL, 8};
|
||||||
|
case SceNgs2WaveFormType::VAG: return {AVSampleFormat::AV_SAMPLE_FMT_FLT, 4};
|
||||||
|
case SceNgs2WaveFormType::ATRAC9: return {AVSampleFormat::AV_SAMPLE_FMT_FLT, 4};
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return {AVSampleFormat::AV_SAMPLE_FMT_NONE, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<AVSampleFormat, uint8_t> convFormatPlanar(SceNgs2WaveFormType type) {
|
||||||
|
switch (type) {
|
||||||
|
case SceNgs2WaveFormType::PCM_U8: return {AVSampleFormat::AV_SAMPLE_FMT_U8P, 1};
|
||||||
|
case SceNgs2WaveFormType::PCM_I16LITTLE: return {AVSampleFormat::AV_SAMPLE_FMT_S16P, 2};
|
||||||
|
case SceNgs2WaveFormType::PCM_I16BIG: return {AVSampleFormat::AV_SAMPLE_FMT_S16P, 2};
|
||||||
|
case SceNgs2WaveFormType::PCM_I24LITTLE: return {AVSampleFormat::AV_SAMPLE_FMT_NONE, 3};
|
||||||
|
case SceNgs2WaveFormType::PCM_I24BIG: return {AVSampleFormat::AV_SAMPLE_FMT_NONE, 3};
|
||||||
|
case SceNgs2WaveFormType::PCM_I32LITTLE: return {AVSampleFormat::AV_SAMPLE_FMT_S32P, 4};
|
||||||
|
case SceNgs2WaveFormType::PCM_I32BIG: return {AVSampleFormat::AV_SAMPLE_FMT_S32P, 4};
|
||||||
|
case SceNgs2WaveFormType::PCM_F32LITTLE: return {AVSampleFormat::AV_SAMPLE_FMT_FLTP, 4};
|
||||||
|
case SceNgs2WaveFormType::PCM_F32BIG: return {AVSampleFormat::AV_SAMPLE_FMT_FLTP, 4};
|
||||||
|
case SceNgs2WaveFormType::PCM_F64LITTLE: return {AVSampleFormat::AV_SAMPLE_FMT_DBLP, 8};
|
||||||
|
case SceNgs2WaveFormType::PCM_F64BIG: return {AVSampleFormat::AV_SAMPLE_FMT_DBLP, 8};
|
||||||
|
case SceNgs2WaveFormType::VAG: return {AVSampleFormat::AV_SAMPLE_FMT_FLTP, 4};
|
||||||
|
case SceNgs2WaveFormType::ATRAC9: return {AVSampleFormat::AV_SAMPLE_FMT_FLTP, 4};
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return {AVSampleFormat::AV_SAMPLE_FMT_NONE, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(AVChannelLayout const& rhs, AVChannelLayout const& lhs) {
|
||||||
|
return rhs.nb_channels == lhs.nb_channels && rhs.u.mask == lhs.u.mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator!=(AVChannelLayout const& rhs, AVChannelLayout const& lhs) {
|
||||||
|
return !(rhs == lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PImpl {
|
||||||
|
std::list<std::function<void(void)>> cleanup;
|
||||||
|
|
||||||
|
uint8_t const* data = nullptr;
|
||||||
|
SceNgs2WaveformBlock block;
|
||||||
|
|
||||||
|
uint32_t curOffset = 0;
|
||||||
|
|
||||||
|
userData_inerBuffer userData = {};
|
||||||
|
AVFormatContext* fmtctx = nullptr;
|
||||||
|
AVStream* astream = nullptr;
|
||||||
|
AVCodec const* codec = nullptr;
|
||||||
|
int stream_idx = 0;
|
||||||
|
|
||||||
|
AVCodecContext* codecContext = nullptr;
|
||||||
|
|
||||||
|
AVFrame* frame = nullptr;
|
||||||
|
AVPacket* packet = nullptr;
|
||||||
|
bool newPacket = true;
|
||||||
|
|
||||||
|
SwrContext* swrCtx = nullptr;
|
||||||
|
|
||||||
|
AVChannelLayout curChannelLayoutIn;
|
||||||
|
AVChannelLayout curChannelLayoutOut;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Reader::Reader(SceNgs2Handle_voice* voice): voice(voice) {
|
||||||
|
m_pimpl = std::make_unique<PImpl>().release();
|
||||||
|
}
|
||||||
|
|
||||||
|
Reader::~Reader() {
|
||||||
|
delete (PImpl*)m_pimpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Reader::init(SceNgs2SamplerVoiceWaveformBlocksParam const* param) {
|
||||||
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
|
||||||
|
auto pimpl = (PImpl*)m_pimpl;
|
||||||
|
|
||||||
|
if (param->data == nullptr) {
|
||||||
|
// Reset
|
||||||
|
voice->state.bits.Empty = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
m_isInit = false;
|
||||||
|
|
||||||
|
pimpl->data = (uint8_t const*)param->data;
|
||||||
|
pimpl->block = param->aBlock[0];
|
||||||
|
pimpl->curOffset = 0;
|
||||||
|
|
||||||
|
// m_state.numDecodedSamples = 0;
|
||||||
|
// m_state.decodedDataSize = 0;
|
||||||
|
|
||||||
|
if (voice->info.type != SceNgs2WaveFormType::ATRAC9 && voice->info.type != SceNgs2WaveFormType::VAG) {
|
||||||
|
m_isCompressed = false;
|
||||||
|
m_isInit = true;
|
||||||
|
|
||||||
|
voice->state.bits.Empty = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check if riff or uncompressed
|
||||||
|
auto riffHeader = (RiffWaveHeader const*)param->data;
|
||||||
|
if (memcmp(riffHeader->chunkID, "RIFF", 4) != 0 || memcmp(riffHeader->riffType, "WAVE", 4) != 0) {
|
||||||
|
m_isCompressed = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse riff
|
||||||
|
m_isCompressed = true;
|
||||||
|
|
||||||
|
auto cleanup = &pimpl->cleanup;
|
||||||
|
auto userData = &pimpl->userData;
|
||||||
|
|
||||||
|
userData->ptr = param->data;
|
||||||
|
userData->size = param->aBlock[0].offset + param->aBlock[0].size;
|
||||||
|
userData->curOffset = 0;
|
||||||
|
|
||||||
|
pimpl->newPacket = true;
|
||||||
|
|
||||||
|
// Init Setup
|
||||||
|
auto aBufferIo = (uint8_t*)av_malloc(4096 + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
|
||||||
|
AVIOContext* avioctx = avio_alloc_context(aBufferIo, 4096, 0, userData, readFunc_linearBuffer, nullptr, seekFunc_linearBuffer);
|
||||||
|
|
||||||
|
cleanup->emplace_back([&] { av_free(avioctx); });
|
||||||
|
cleanup->emplace_back([&] { av_free(aBufferIo); });
|
||||||
|
|
||||||
|
// Open the input
|
||||||
|
pimpl->fmtctx = avformat_alloc_context();
|
||||||
|
|
||||||
|
// pimpl->fmtctx->pb = avioctx;
|
||||||
|
// pimpl->fmtctx->flags |= AVFMT_FLAG_CUSTOM_IO;
|
||||||
|
|
||||||
|
int ret = avformat_open_input(&pimpl->fmtctx, "F:/down2/atrac9mem/snd0.at9", nullptr, nullptr);
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERR(L"Reader: ffmpeg failed to read passed data: %d", ret);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup->emplace_back([&] { avformat_close_input(&pimpl->fmtctx); });
|
||||||
|
|
||||||
|
if (int res = avformat_find_stream_info(pimpl->fmtctx, NULL) < 0; res < 0) {
|
||||||
|
LOG_ERR(L"avformat_find_stream_info result:%d", res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (auto i = 0; i < pimpl->fmtctx->nb_streams; ++i) {
|
||||||
|
if (pimpl->fmtctx->streams[i]->codecpar->codec_type == AVMediaType::AVMEDIA_TYPE_AUDIO) {
|
||||||
|
pimpl->astream = pimpl->fmtctx->streams[i];
|
||||||
|
pimpl->stream_idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pimpl->codec = avcodec_find_decoder(pimpl->astream->codecpar->codec_id);
|
||||||
|
|
||||||
|
pimpl->codecContext = avcodec_alloc_context3(pimpl->codec);
|
||||||
|
if (auto err = avcodec_parameters_to_context(pimpl->codecContext, pimpl->astream->codecpar); err != 0) {
|
||||||
|
LOG_ERR(L"Reader: avcodec_parameters_to_context err:%d", err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cleanup->emplace_back([&] { avcodec_free_context(&pimpl->codecContext); });
|
||||||
|
|
||||||
|
// Setup multithreading
|
||||||
|
if (pimpl->codec->capabilities | AV_CODEC_CAP_FRAME_THREADS)
|
||||||
|
pimpl->codecContext->thread_type = FF_THREAD_FRAME;
|
||||||
|
else if (pimpl->codec->capabilities | AV_CODEC_CAP_SLICE_THREADS)
|
||||||
|
pimpl->codecContext->thread_type = FF_THREAD_SLICE;
|
||||||
|
else
|
||||||
|
pimpl->codecContext->thread_count = 1; // don't use multithreading
|
||||||
|
// -
|
||||||
|
|
||||||
|
if (auto err = avcodec_open2(pimpl->codecContext, pimpl->codec, NULL); err < 0) {
|
||||||
|
LOG_ERR(L"Reader: avcodec_open2 err:%d", err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pimpl->frame = av_frame_alloc();
|
||||||
|
cleanup->emplace_back([&] { av_frame_free(&pimpl->frame); });
|
||||||
|
|
||||||
|
pimpl->packet = av_packet_alloc();
|
||||||
|
cleanup->emplace_back([&] { av_packet_free(&pimpl->packet); });
|
||||||
|
|
||||||
|
m_isInit = true;
|
||||||
|
voice->state.bits.Empty = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reader::setNewData(void const* start, void const* end) {
|
||||||
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
auto pimpl = (PImpl*)m_pimpl;
|
||||||
|
|
||||||
|
pimpl->curOffset = 0;
|
||||||
|
pimpl->data = (uint8_t const*)start;
|
||||||
|
pimpl->block.size = (uint64_t)end - (uint64_t)start;
|
||||||
|
|
||||||
|
voice->state.bits.Empty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Reader::getAudioUncompressed(SceNgs2RenderBufferInfo* rbi, uint32_t numOutSamples) {
|
||||||
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
auto pimpl = (PImpl*)m_pimpl;
|
||||||
|
|
||||||
|
auto const channelLayoutOut = convChannelLayout(rbi->channelsCount);
|
||||||
|
auto const channelLayoutIn = convChannelLayout(voice->info.channelsCount);
|
||||||
|
|
||||||
|
if (pimpl->swrCtx == nullptr || channelLayoutOut != pimpl->curChannelLayoutOut || channelLayoutIn != pimpl->curChannelLayoutIn) {
|
||||||
|
pimpl->curChannelLayoutOut = convChannelLayout(rbi->channelsCount);
|
||||||
|
pimpl->curChannelLayoutIn = convChannelLayout(voice->info.channelsCount);
|
||||||
|
if (pimpl->curChannelLayoutOut.order == AV_CHANNEL_ORDER_UNSPEC || pimpl->curChannelLayoutIn.order == AV_CHANNEL_ORDER_UNSPEC) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const [formatOut, bytesOut] = convFormat(rbi->waveType);
|
||||||
|
if (formatOut == AVSampleFormat::AV_SAMPLE_FMT_NONE) return false;
|
||||||
|
|
||||||
|
auto const [formatIn, bytesIn] = convFormat(voice->info.type);
|
||||||
|
if (formatIn == AVSampleFormat::AV_SAMPLE_FMT_NONE) return false;
|
||||||
|
|
||||||
|
if (swr_alloc_set_opts2(&pimpl->swrCtx, &pimpl->curChannelLayoutOut, formatOut, voice->info.sampleRate, &pimpl->curChannelLayoutIn, formatIn,
|
||||||
|
voice->info.sampleRate, 0, NULL)) {
|
||||||
|
LOG_ERR(L"Reader:Couldn't alloc swr");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
swr_init(pimpl->swrCtx);
|
||||||
|
pimpl->cleanup.emplace_back([&] { swr_free(&pimpl->swrCtx); });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check repeat
|
||||||
|
if (pimpl->block.size <= pimpl->curOffset) {
|
||||||
|
if (pimpl->block.numRepeat > 0) {
|
||||||
|
pimpl->curOffset = 0;
|
||||||
|
--pimpl->block.numRepeat;
|
||||||
|
} else {
|
||||||
|
voice->state.data = 0;
|
||||||
|
|
||||||
|
voice->state.bits.Empty = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// -
|
||||||
|
|
||||||
|
uint32_t const readSize = std::min(rbi->bufferSize, (size_t)pimpl->block.size - pimpl->curOffset);
|
||||||
|
|
||||||
|
auto const [formatIn, bytesIn] = convFormat(voice->info.type);
|
||||||
|
auto const [formatOut, bytesOut] = convFormat(rbi->waveType);
|
||||||
|
|
||||||
|
std::vector<uint8_t*> audioBuffers(((int)rbi->channelsCount));
|
||||||
|
|
||||||
|
auto const channelSizeOut = (uint32_t)rbi->channelsCount * bytesOut;
|
||||||
|
for (uint8_t n = 0; n < audioBuffers.size(); ++n) {
|
||||||
|
audioBuffers[n] = &((uint8_t*)rbi->bufferPtr)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pimpl->block.numSamples > 0) {
|
||||||
|
std::vector<uint8_t const*> audioBuffersIn(((int)voice->info.channelsCount));
|
||||||
|
|
||||||
|
auto const channelSizeIn = (uint32_t)voice->info.channelsCount * bytesOut;
|
||||||
|
for (uint8_t n = 0; n < audioBuffersIn.size(); ++n) {
|
||||||
|
audioBuffersIn[n] = &((uint8_t*)pimpl->data)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto numSamples = swr_convert(pimpl->swrCtx, (uint8_t**)&rbi->bufferPtr, numOutSamples, &pimpl->data, pimpl->block.numSamples);
|
||||||
|
|
||||||
|
pimpl->block.numSamples = 0;
|
||||||
|
} else {
|
||||||
|
auto numSamples = swr_convert(pimpl->swrCtx, (uint8_t**)&rbi->bufferPtr, numOutSamples, nullptr, 0);
|
||||||
|
if (numSamples == 0) {
|
||||||
|
m_state.numDecodedSamples += pimpl->block.numSamples;
|
||||||
|
m_state.decodedDataSize += pimpl->block.size;
|
||||||
|
voice->state.bits.Empty = true;
|
||||||
|
|
||||||
|
pimpl->curOffset = pimpl->block.size;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Reader::getAudioCompressed(SceNgs2RenderBufferInfo* rbi) {
|
||||||
|
LOG_USE_MODULE(libSceNgs2);
|
||||||
|
|
||||||
|
auto pimpl = (PImpl*)m_pimpl;
|
||||||
|
|
||||||
|
// if (pimpl->swrCtx == nullptr) {
|
||||||
|
// auto optDstChLayout = convChannelLayout(rbi->channelsCount);
|
||||||
|
// if (!optDstChLayout) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// auto const [format, bytesOut] = convFormat(rbi->waveType);
|
||||||
|
// if (format == AVSampleFormat::AV_SAMPLE_FMT_NONE) return false;
|
||||||
|
|
||||||
|
// if (swr_alloc_set_opts2(&pimpl->swrCtx, &(*optDstChLayout), format, voice->info.sampleRate, &pimpl->codecContext->ch_layout,
|
||||||
|
// pimpl->codecContext->sample_fmt, pimpl->codecContext->sample_rate, 0, NULL)) {
|
||||||
|
// LOG_ERR(L"Reader:Couldn't alloc swr");
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// swr_init(pimpl->swrCtx);
|
||||||
|
// pimpl->cleanup.emplace_back([&] { swr_free(&pimpl->swrCtx); });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// size_t offset = 0;
|
||||||
|
|
||||||
|
// while (offset < rbi->bufferSize) {
|
||||||
|
// // Get a new packet
|
||||||
|
// if (pimpl->newPacket) {
|
||||||
|
// pimpl->packet->dts = AV_NOPTS_VALUE;
|
||||||
|
// pimpl->packet->pts = AV_NOPTS_VALUE;
|
||||||
|
|
||||||
|
// int state = av_read_frame(pimpl->fmtctx, pimpl->packet);
|
||||||
|
// if (state < 0) {
|
||||||
|
// if (state != AVERROR_EOF) {
|
||||||
|
// LOG_ERR(L"av_read_frame error %d", state);
|
||||||
|
// } else {
|
||||||
|
// voice->state.bits.Empty = true;
|
||||||
|
// }
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Skip if not a audio packet
|
||||||
|
// if (pimpl->packet->stream_index != pimpl->stream_idx) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pimpl->newPacket = false;
|
||||||
|
// }
|
||||||
|
// // -
|
||||||
|
|
||||||
|
// // Process packet
|
||||||
|
// if (int ret = avcodec_send_packet(pimpl->codecContext, pimpl->packet); ret < 0) {
|
||||||
|
// if (ret == AVERROR(EAGAIN)) {
|
||||||
|
// av_packet_unref(pimpl->packet);
|
||||||
|
// pimpl->newPacket = true;
|
||||||
|
// continue; // Get new frame
|
||||||
|
// } else if (ret == AVERROR_EOF) {
|
||||||
|
// voice->state.bits.Empty = true;
|
||||||
|
// } else {
|
||||||
|
// voice->state.bits.Error = true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// av_packet_unref(pimpl->packet);
|
||||||
|
// //- packet
|
||||||
|
|
||||||
|
// // Now the frames
|
||||||
|
// auto const retRecv = avcodec_receive_frame(pimpl->codecContext, pimpl->frame);
|
||||||
|
|
||||||
|
// int outNumSamples = swr_get_out_samples(pimpl->swrCtx, pimpl->frame->nb_samples);
|
||||||
|
|
||||||
|
// // todo get sample size, nb_channels is zero (fix)
|
||||||
|
// auto const [format, bytesOut] = convFormat(rbi->waveType);
|
||||||
|
// auto const channelSize = (uint32_t)outNumSamples * av_get_bytes_per_sample(format);
|
||||||
|
|
||||||
|
// std::vector<uint8_t*> audioBuffers(((int)rbi->channelsCount));
|
||||||
|
// for (uint8_t n = 0; n < audioBuffers.size(); ++n) {
|
||||||
|
// audioBuffers[n] = &((uint8_t*)rbi->bufferPtr)[offset + n * channelSize];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for (int i = 0; i < rbi->bufferSize / 4; ++i) { // Filling the chanels with data
|
||||||
|
// // We should fill all the channels with available data, it seems.
|
||||||
|
// // The sound plays slightly quieter if we fill only two first channels.
|
||||||
|
// ((float*)rbi->bufferPtr)[offset + i] = ((float*)pimpl->frame->data[i % pimpl->frame->ch_layout.nb_channels])[i / (int)rbi->channelsCount];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // uint8_t* audioBuffers[8] = {&((uint8_t*)rbi->bufferPtr)[offset], &((uint8_t*)rbi->bufferPtr)[offset],
|
||||||
|
// // &((uint8_t*)rbi->bufferPtr)[offset],&((uint8_t*)rbi->bufferPtr)[offset],&((uint8_t*)rbi->bufferPtr)[offset],&((uint8_t*)rbi->bufferPtr)[offset],};
|
||||||
|
|
||||||
|
// // if (outNumSamples = swr_convert(pimpl->swrCtx, audioBuffers.data(), outNumSamples, (uint8_t const**)pimpl->frame->extended_data,
|
||||||
|
// // pimpl->frame->nb_samples);
|
||||||
|
// // outNumSamples < 0) {
|
||||||
|
// // LOG_WARN(L"swr_convert");
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// av_frame_unref(pimpl->frame);
|
||||||
|
// // -
|
||||||
|
|
||||||
|
// auto const bufferSize_ = (uint32_t)rbi->channelsCount * channelSize;
|
||||||
|
|
||||||
|
// // float* samples = (float*)(&((uint8_t*)rbi->bufferPtr)[offset]);
|
||||||
|
// // for (int i = 0; i < outNumSamples * (int)rbi->channelsCount; i++) {
|
||||||
|
// // samples[i] *= 100000.0;
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// offset += (uint32_t)rbi->channelsCount * channelSize;
|
||||||
|
// }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Reader::getAudio(SceNgs2RenderBufferInfo* rbi, uint32_t numOutSamples) {
|
||||||
|
if (m_isInit == false || voice->state.bits.Empty || !voice->state.bits.Playing || (voice->state.bits.Playing && voice->state.bits.Paused)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_isCompressed) {
|
||||||
|
return false; // getAudioCompressed(rbi);
|
||||||
|
} else {
|
||||||
|
return getAudioUncompressed(rbi, numOutSamples);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
31
modules/libSceNgs2/reader.h
Normal file
31
modules/libSceNgs2/reader.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
class Reader {
|
||||||
|
void* m_pimpl;
|
||||||
|
bool m_isInit = false;
|
||||||
|
bool m_isCompressed = false;
|
||||||
|
|
||||||
|
SceNgs2Handle_voice* voice;
|
||||||
|
|
||||||
|
SceNgs2SamplerVoiceState m_state;
|
||||||
|
|
||||||
|
bool getAudioUncompressed(SceNgs2RenderBufferInfo*, uint32_t numOutSamples);
|
||||||
|
bool getAudioCompressed(SceNgs2RenderBufferInfo*);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Reader(SceNgs2Handle_voice* voice);
|
||||||
|
~Reader();
|
||||||
|
|
||||||
|
bool init(SceNgs2SamplerVoiceWaveformBlocksParam const* param);
|
||||||
|
|
||||||
|
bool getAudio(SceNgs2RenderBufferInfo*, uint32_t numOutSamples);
|
||||||
|
|
||||||
|
void setNewData(void const* start, void const* end);
|
||||||
|
|
||||||
|
void getState(SceNgs2SamplerVoiceState* state) const {
|
||||||
|
*state = m_state;
|
||||||
|
state->voiceState = voice->state;
|
||||||
|
}
|
||||||
|
};
|
24
modules/libSceNgs2/riffTypes.h
Normal file
24
modules/libSceNgs2/riffTypes.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct RiffHeader {
|
||||||
|
unsigned char chunkID[4]; // RIFF
|
||||||
|
uint32_t chunkSize;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct RiffWaveHeader {
|
||||||
|
unsigned char chunkID[4]; // RIFF
|
||||||
|
uint32_t chunkSize;
|
||||||
|
unsigned char riffType[4]; // WAVE
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct RiffFormatHeader {
|
||||||
|
unsigned char chunkID[4]; // RIFF
|
||||||
|
uint32_t chunkSize;
|
||||||
|
uint16_t audioFormat;
|
||||||
|
uint16_t numChannels;
|
||||||
|
uint32_t sampleRate; // Sampling Frequency in Hz
|
||||||
|
uint32_t avgByteRate; // ~bytes per second
|
||||||
|
uint16_t frameSize; // BlockAlign
|
||||||
|
uint16_t bitsPerSample;
|
||||||
|
} __attribute__((packed));
|
@ -1,6 +1,32 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "..\libSceCommonDialog\types.h"
|
#include "..\libSceCommonDialog\types.h"
|
||||||
#include "codes.h"
|
#include "codes.h"
|
||||||
|
#include "utility/utility.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
union SceNgs2VoiceStateFlags {
|
||||||
|
uint32_t data;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool Inuse : 1 = false;
|
||||||
|
bool Playing : 1 = false;
|
||||||
|
bool Paused : 1 = false;
|
||||||
|
bool Stopped : 1 = false;
|
||||||
|
bool Error : 1 = false;
|
||||||
|
bool Empty : 1 = true;
|
||||||
|
} bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SceNgs2VoiceEvent : uint32_t {
|
||||||
|
Play,
|
||||||
|
Stop,
|
||||||
|
Stop_imm,
|
||||||
|
Kill,
|
||||||
|
Pause,
|
||||||
|
Resume,
|
||||||
|
};
|
||||||
|
|
||||||
enum class SceNgs2WaveFormType : uint32_t {
|
enum class SceNgs2WaveFormType : uint32_t {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
@ -41,7 +67,8 @@ enum class SceNgs2ChannelsCount : uint32_t {
|
|||||||
INVALID = 0xFFFFFFFF
|
INVALID = 0xFFFFFFFF
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SceNgs2VoiceParam : uint32_t {
|
// Voice events
|
||||||
|
enum class SceNgs2VoiceParam : uint16_t {
|
||||||
SET_MATRIX_LEVELS = 1,
|
SET_MATRIX_LEVELS = 1,
|
||||||
SET_PORT_VOLUME,
|
SET_PORT_VOLUME,
|
||||||
SET_PORT_MATRIX,
|
SET_PORT_MATRIX,
|
||||||
@ -51,6 +78,64 @@ enum class SceNgs2VoiceParam : uint32_t {
|
|||||||
SET_CALLBACK,
|
SET_CALLBACK,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Master events
|
||||||
|
enum class SceNgs2MasteringParam : uint16_t {
|
||||||
|
SETUP,
|
||||||
|
SET_MATRIX,
|
||||||
|
SET_LFE,
|
||||||
|
SET_LIMITER,
|
||||||
|
SET_GAIN,
|
||||||
|
SET_OUTPUT,
|
||||||
|
SET_PEAK_METER,
|
||||||
|
};
|
||||||
|
|
||||||
|
// sampler events
|
||||||
|
enum class SceNgs2SamplerParam : uint16_t {
|
||||||
|
SETUP,
|
||||||
|
ADD_WAVEFORM_BLOCKS,
|
||||||
|
REPLACE_WAVEFORM_ADDRESS,
|
||||||
|
SET_WAVEFORM_FRAME_OFFSET,
|
||||||
|
EXIT_LOOP,
|
||||||
|
SET_PITCH,
|
||||||
|
SET_ENVELOPE,
|
||||||
|
SET_DISTORTION,
|
||||||
|
SET_USER_FX,
|
||||||
|
SET_PEAK_METER,
|
||||||
|
SET_FILTER,
|
||||||
|
};
|
||||||
|
// Submixer events
|
||||||
|
enum class SceNgs2SubmixerParam : uint16_t {
|
||||||
|
SETUP,
|
||||||
|
SET_ENVELOPE,
|
||||||
|
SET_COMPRESSOR,
|
||||||
|
SET_DISTORTION,
|
||||||
|
SET_USER_FX,
|
||||||
|
SET_PEAK_METER,
|
||||||
|
SET_FILTER,
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
struct SceNgs2WaveformInfo {
|
||||||
|
SceNgs2WaveFormType type = SceNgs2WaveFormType::NONE;
|
||||||
|
SceNgs2ChannelsCount channelsCount = SceNgs2ChannelsCount::INVALID;
|
||||||
|
uint32_t sampleRate = 0;
|
||||||
|
uint32_t configData;
|
||||||
|
uint32_t frameOffset;
|
||||||
|
uint32_t frameMargin;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Reader;
|
||||||
|
|
||||||
|
struct SceNgs2VoiceHandle {
|
||||||
|
SceNgs2VoiceHandle() = default;
|
||||||
|
~SceNgs2VoiceHandle() = default;
|
||||||
|
|
||||||
|
SceNgs2VoiceStateFlags state = {0};
|
||||||
|
|
||||||
|
Reader* reader = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
struct SceNgs2ContextBufferInfo {
|
struct SceNgs2ContextBufferInfo {
|
||||||
void* hostBuffer;
|
void* hostBuffer;
|
||||||
size_t hostBufferSize;
|
size_t hostBufferSize;
|
||||||
@ -59,8 +144,8 @@ struct SceNgs2ContextBufferInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct SceNgs2BufferAllocator {
|
struct SceNgs2BufferAllocator {
|
||||||
int32_t SYSV_ABI (*allocHandler)(SceNgs2ContextBufferInfo*);
|
int32_t SYSV_ABI (*allocHandler)(SceNgs2ContextBufferInfo*) = nullptr;
|
||||||
int32_t SYSV_ABI (*freeHandler)(SceNgs2ContextBufferInfo*);
|
int32_t SYSV_ABI (*freeHandler)(SceNgs2ContextBufferInfo*) = nullptr;
|
||||||
void* userData;
|
void* userData;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -105,30 +190,85 @@ struct SceNgs2SystemInfo {
|
|||||||
uint32_t numGrainSamples;
|
uint32_t numGrainSamples;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SceNgs2SystemHandle {
|
struct SceNgs2RackOption {
|
||||||
SceNgs2SystemInfo info;
|
size_t size = sizeof(SceNgs2RackOption);
|
||||||
|
|
||||||
|
char name[SCE_NGS2_RACK_NAME_LENGTH] = "\0";
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t maxGrainSamples = 1;
|
||||||
|
uint32_t maxVoices = 1;
|
||||||
|
uint32_t maxInputDelayBlocks = 1;
|
||||||
|
uint32_t maxMatrices = 1;
|
||||||
|
uint32_t maxPorts = 1;
|
||||||
|
|
||||||
|
uint32_t aReserved[20];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SceNgs2RackHandle {
|
struct SceNgs2VoiceState {
|
||||||
SceNgs2RackInfo info;
|
uint32_t stateFlags = 0;
|
||||||
SceNgs2Handle* voices;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SceNgs2VoiceHandle {
|
enum class SceNgs2HandleType { System, Rack, Voice };
|
||||||
std::vector<AVPacket>* data;
|
|
||||||
};
|
struct SceNgs2Handle_rack;
|
||||||
|
|
||||||
struct SceNgs2Handle {
|
struct SceNgs2Handle {
|
||||||
SceNgs2Handle* owner;
|
SceNgs2HandleType const type;
|
||||||
bool allocSet;
|
|
||||||
SceNgs2BufferAllocator alloc;
|
|
||||||
SceNgs2ContextBufferInfo cbi;
|
|
||||||
|
|
||||||
union _ngsTypes {
|
SceNgs2Handle(SceNgs2HandleType type): type(type) {}
|
||||||
SceNgs2SystemHandle sys;
|
|
||||||
SceNgs2RackHandle rack;
|
virtual ~SceNgs2Handle() = default;
|
||||||
SceNgs2VoiceHandle voice;
|
};
|
||||||
} un;
|
|
||||||
|
struct SceNgs2Handle_system: public SceNgs2Handle {
|
||||||
|
SceNgs2BufferAllocator alloc;
|
||||||
|
|
||||||
|
// Racks
|
||||||
|
SceNgs2Handle_rack* mastering = nullptr;
|
||||||
|
SceNgs2Handle_rack* sampler = nullptr;
|
||||||
|
SceNgs2Handle_rack* submixer = nullptr;
|
||||||
|
SceNgs2Handle_rack* reverb = nullptr;
|
||||||
|
SceNgs2Handle_rack* equalizer = nullptr;
|
||||||
|
|
||||||
|
// -
|
||||||
|
|
||||||
|
SceNgs2Handle_system(SceNgs2BufferAllocator const* alloc_): SceNgs2Handle(SceNgs2HandleType::System) {
|
||||||
|
if (alloc_ != nullptr) alloc = *alloc_;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~SceNgs2Handle_system() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceNgs2Handle_voice: public SceNgs2Handle {
|
||||||
|
SceNgs2Handle_rack* parent;
|
||||||
|
|
||||||
|
SceNgs2VoiceStateFlags state {};
|
||||||
|
SceNgs2WaveformInfo info;
|
||||||
|
|
||||||
|
Reader* reader = nullptr; // optional, depends on racktype
|
||||||
|
|
||||||
|
SceNgs2Handle_voice(SceNgs2Handle_rack* parent): SceNgs2Handle(SceNgs2HandleType::Voice), parent(parent) {}
|
||||||
|
|
||||||
|
virtual ~SceNgs2Handle_voice();
|
||||||
|
|
||||||
|
void ev_KickEvent(SceNgs2VoiceEvent id);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceNgs2Handle_rack: public SceNgs2Handle {
|
||||||
|
uint32_t const rackId;
|
||||||
|
|
||||||
|
SceNgs2Handle_system* parent;
|
||||||
|
|
||||||
|
SceNgs2RackOption options;
|
||||||
|
|
||||||
|
std::map<int, SceNgs2Handle_voice> voices; // address of SceNgs2Handle_voice must be valid !
|
||||||
|
|
||||||
|
SceNgs2Handle_rack(SceNgs2Handle_system* parent, SceNgs2RackOption const* options_, uint32_t rackId)
|
||||||
|
: SceNgs2Handle(SceNgs2HandleType::Rack), rackId(rackId), parent(parent) {
|
||||||
|
if (options_ != nullptr) memcpy(&options, options_, sizeof(SceNgs2RackOption));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~SceNgs2Handle_rack() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SceNgs2RenderBufferInfo {
|
struct SceNgs2RenderBufferInfo {
|
||||||
@ -138,21 +278,12 @@ struct SceNgs2RenderBufferInfo {
|
|||||||
SceNgs2ChannelsCount channelsCount;
|
SceNgs2ChannelsCount channelsCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SceNgs2WaveformInfo {
|
|
||||||
SceNgs2WaveFormType type;
|
|
||||||
SceNgs2ChannelsCount channelsCount;
|
|
||||||
uint32_t sampleRate;
|
|
||||||
uint32_t configData;
|
|
||||||
uint32_t frameOffset;
|
|
||||||
uint32_t frameMargin;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SceNgs2WaveformBlock {
|
struct SceNgs2WaveformBlock {
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t : 32;
|
uint32_t numRepeat;
|
||||||
uint32_t : 32;
|
uint32_t skipSamples;
|
||||||
uint32_t : 32;
|
uint32_t numSamples;
|
||||||
uint32_t : 32;
|
uint32_t : 32;
|
||||||
uintptr_t userData;
|
uintptr_t userData;
|
||||||
};
|
};
|
||||||
@ -166,10 +297,11 @@ struct SceNgs2WaveformFormat {
|
|||||||
uint32_t samplesCount;
|
uint32_t samplesCount;
|
||||||
uint32_t : 32;
|
uint32_t : 32;
|
||||||
uint32_t : 32;
|
uint32_t : 32;
|
||||||
uint32_t : 32;
|
uint32_t dataPerFrame;
|
||||||
uint32_t : 32;
|
uint32_t frameSize;
|
||||||
uint32_t : 32;
|
uint32_t numframeSamples;
|
||||||
uint32_t : 32;
|
uint32_t samplesDelay;
|
||||||
|
|
||||||
uint32_t numBlocks;
|
uint32_t numBlocks;
|
||||||
SceNgs2WaveformBlock block[4];
|
SceNgs2WaveformBlock block[4];
|
||||||
};
|
};
|
||||||
@ -252,6 +384,33 @@ struct SceNgs2SamplerVoiceWaveformBlocksParam {
|
|||||||
const SceNgs2WaveformBlock* aBlock;
|
const SceNgs2WaveformBlock* aBlock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SceNgs2CustomSamplerVoiceWaveformAddressParam {
|
||||||
|
SceNgs2VoiceParamHead header;
|
||||||
|
const void* pDataStart;
|
||||||
|
const void* pDataEnd;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceNgs2SamplerVoiceSetupParam {
|
||||||
|
SceNgs2VoiceParamHead header;
|
||||||
|
SceNgs2WaveformInfo format;
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceNgs2SamplerVoiceState {
|
||||||
|
SceNgs2VoiceStateFlags voiceState = {0};
|
||||||
|
|
||||||
|
float envelopeHeight = 0;
|
||||||
|
float peakHeight = 0;
|
||||||
|
uint32_t reserved;
|
||||||
|
uint64_t numDecodedSamples = 0;
|
||||||
|
uint64_t decodedDataSize = 0;
|
||||||
|
uint64_t userData = 0;
|
||||||
|
const void* waveformData = 0;
|
||||||
|
|
||||||
|
SceNgs2SamplerVoiceState() = default;
|
||||||
|
};
|
||||||
|
|
||||||
struct SceNgs2VoiceCallbackInfo {
|
struct SceNgs2VoiceCallbackInfo {
|
||||||
uintptr_t callbackData;
|
uintptr_t callbackData;
|
||||||
SceNgs2Handle* voiceHandle;
|
SceNgs2Handle* voiceHandle;
|
||||||
@ -280,22 +439,6 @@ struct SceNgs2VoiceCallbackParam {
|
|||||||
uint32_t reserved;
|
uint32_t reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SceNgs2VoiceState {
|
|
||||||
uint32_t stateFlags;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SceNgs2RackOption {
|
|
||||||
size_t size;
|
|
||||||
char name[SCE_NGS2_RACK_NAME_LENGTH];
|
|
||||||
uint32_t flags;
|
|
||||||
uint32_t maxGrainSamples;
|
|
||||||
uint32_t maxVoices;
|
|
||||||
uint32_t maxInputDelayBlocks;
|
|
||||||
uint32_t maxMatrices;
|
|
||||||
uint32_t maxPorts;
|
|
||||||
uint32_t aReserved[20];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SceNgs2CustomModuleInfo {
|
struct SceNgs2CustomModuleInfo {
|
||||||
uint32_t moduleId;
|
uint32_t moduleId;
|
||||||
uint32_t sourceBufferId;
|
uint32_t sourceBufferId;
|
||||||
@ -332,3 +475,5 @@ struct SceNgs2PanParam {
|
|||||||
float fbwLevel;
|
float fbwLevel;
|
||||||
float lfeLevel;
|
float lfeLevel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
@ -17,7 +17,7 @@ EXPORT SYSV_ABI int32_t sceNpPartyInitialize() {
|
|||||||
|
|
||||||
EXPORT SYSV_ABI int32_t sceNpPartyCheckCallback() {
|
EXPORT SYSV_ABI int32_t sceNpPartyCheckCallback() {
|
||||||
LOG_USE_MODULE(libSceNpParty);
|
LOG_USE_MODULE(libSceNpParty);
|
||||||
LOG_ERR(L"todo %S", __FUNCTION__);
|
LOG_TRACE(L"todo %S", __FUNCTION__);
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +87,7 @@ EXPORT SYSV_ABI int32_t scePlayGoSetInstallSpeed(ScePlayGoHandle handle, ScePlay
|
|||||||
EXPORT SYSV_ABI int32_t scePlayGoGetInstallSpeed(ScePlayGoHandle handle, ScePlayGoInstallSpeed* speed) {
|
EXPORT SYSV_ABI int32_t scePlayGoGetInstallSpeed(ScePlayGoHandle handle, ScePlayGoInstallSpeed* speed) {
|
||||||
LOG_USE_MODULE(libScePlayGo);
|
LOG_USE_MODULE(libScePlayGo);
|
||||||
LOG_ERR(L"TODO: %S", __FUNCTION__);
|
LOG_ERR(L"TODO: %S", __FUNCTION__);
|
||||||
|
*speed = 2;
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,14 @@ EXPORT SYSV_ABI int __NID(sem_post)(boost::interprocess::interprocess_semaphore*
|
|||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPORT SYSV_ABI int __NID(sem_getvalue)(boost::interprocess::interprocess_semaphore** sem) {
|
||||||
|
if (sem == nullptr || *sem == nullptr) {
|
||||||
|
return POSIX_SET(ErrCode::_ESRCH);
|
||||||
|
}
|
||||||
|
return (*sem)->get_count();
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
|
||||||
EXPORT SYSV_ABI int __NID(sem_reltimedwait_np)(boost::interprocess::interprocess_semaphore** sem, SceKernelTimespec* reltime) {
|
EXPORT SYSV_ABI int __NID(sem_reltimedwait_np)(boost::interprocess::interprocess_semaphore** sem, SceKernelTimespec* reltime) {
|
||||||
auto now = boost::posix_time::microsec_clock::universal_time();
|
auto now = boost::posix_time::microsec_clock::universal_time();
|
||||||
auto timeout = boost::posix_time::seconds(reltime->tv_sec) + boost::posix_time::microsec(reltime->tv_nsec / 1000);
|
auto timeout = boost::posix_time::seconds(reltime->tv_sec) + boost::posix_time::microsec(reltime->tv_nsec / 1000);
|
||||||
|
@ -62,7 +62,7 @@ EXPORT SYSV_ABI void __NID(__stack_chk_fail)() {
|
|||||||
|
|
||||||
EXPORT SYSV_ABI void __NID(_exit)(int code) {
|
EXPORT SYSV_ABI void __NID(_exit)(int code) {
|
||||||
LOG_USE_MODULE(libkernel);
|
LOG_USE_MODULE(libkernel);
|
||||||
LOG_INFO(L"exit code:%d", code);
|
LOG_ERR(L"exit code:%d", code);
|
||||||
|
|
||||||
::exit(code);
|
::exit(code);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user