From 894a75ad6baf425cf2379bca0252a8d88d34c4e7 Mon Sep 17 00:00:00 2001 From: Martin Baliet Date: Wed, 8 May 2024 14:19:07 +0200 Subject: [PATCH] ngs2| dump --- modules/libSceAudioOut/entry.cpp | 14 +- modules/libSceNgs2/entry.cpp | 88 ++++----- modules/libSceNgs2/readFuncs.cpp | 145 ++++++++------- modules/libSceNgs2/readFuncs.h | 2 +- modules/libSceNgs2/reader.cpp | 298 +++++++++++++++++++------------ modules/libSceNgs2/reader.h | 12 +- modules/libSceNgs2/riffTypes.h | 24 +++ modules/libSceNgs2/types.h | 6 +- 8 files changed, 350 insertions(+), 239 deletions(-) create mode 100644 modules/libSceNgs2/riffTypes.h diff --git a/modules/libSceAudioOut/entry.cpp b/modules/libSceAudioOut/entry.cpp index b30a9bb..ce159c1 100644 --- a/modules/libSceAudioOut/entry.cpp +++ b/modules/libSceAudioOut/entry.cpp @@ -20,7 +20,7 @@ struct PortOut { SceAudioOutPortType type = SceAudioOutPortType::MAIN; uint8_t sampleSize = 0; uint32_t samplesNum = 0; - uint32_t freq = 0; + uint32_t sampleRate = 0; uint32_t queued = 0; SceAudioOutParamFormat format = SceAudioOutParamFormat::FLOAT_MONO; uint64_t lastOutputTime = 0; @@ -71,7 +71,7 @@ class PortsOut { if (port.deviceName.compare(0, std::string::npos, devName, 0, port.deviceName.length()) != 0) continue; SDL_AudioSpec fmt { - .freq = static_cast(port.freq), + .freq = static_cast(port.sampleRate), .format = port.sdlFormat, .channels = static_cast(port.channelsNum), .samples = static_cast(port.samplesNum), @@ -167,7 +167,7 @@ void syncPort(PortOut* port) { const uint32_t bytesize = bytesize_1ch * port->channelsNum; 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 return; } @@ -237,7 +237,7 @@ EXPORT SYSV_ABI int32_t sceAudioOutInit(void) { 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) { LOG_USE_MODULE(libSceAudioOut); LOG_TRACE(L"%S", __FUNCTION__); auto pimpl = getData(); @@ -259,8 +259,8 @@ EXPORT SYSV_ABI int32_t sceAudioOutOpen(int32_t userId, SceAudioOutPortType type int handle; if (auto port = pimpl->portsOut.AcquirePort(type, &handle)) { port->userId = userId; - port->samplesNum = len; - port->freq = freq; + port->samplesNum = numSamples; + port->sampleRate = sampleRate; port->format = SceAudioOutParamFormat(param & 0x0000007F); if ((param & 0x000F0000) != 0) { @@ -375,7 +375,7 @@ EXPORT SYSV_ABI int32_t sceAudioOutOpen(int32_t userId, SceAudioOutPortType type } SDL_AudioSpec fmt { - .freq = static_cast(freq), + .freq = static_cast(sampleRate), .format = port->sdlFormat, .channels = static_cast(port->channelsNum), .samples = static_cast(port->samplesNum), diff --git a/modules/libSceNgs2/entry.cpp b/modules/libSceNgs2/entry.cpp index ffce1b1..9b7cc5e 100644 --- a/modules/libSceNgs2/entry.cpp +++ b/modules/libSceNgs2/entry.cpp @@ -27,23 +27,26 @@ int32_t _voiceControlWaveformBlock(SceNgs2Handle* voh, const SceNgs2SamplerVoice LOG_USE_MODULE(libSceNgs2); LOG_TRACE(L"waveblock: %d\n", svwfbp->numBlocks); - LOG_TRACE(L"waveptr: %llx\n", svwfbp->data); + LOG_DEBUG(L"waveptr: %llx\n", svwfbp->data); if (voh->type != SceNgs2HandleType::Voice) return Err::Ngs2::INVALID_VOICE_HANDLE; auto voice = (SceNgs2Handle_voice*)voh; - voice->reader = std::make_unique().release(); + if (voice->reader == nullptr) voice->reader = std::make_unique(voice).release(); + + // svwfbp->data can be nullptr! if (!voice->reader->init(svwfbp)) { return Err::Ngs2::INVALID_WAVEFORM_DATA; } - voice->state.bits.Empty = false; - LOG_DEBUG(L"waveptr voice:0x%08llx %llx", (uint64_t)voh, svwfbp->data); return Ok; } int32_t voiceControl_voice(SceNgs2Handle* voh, const SceNgs2VoiceParamHead* phead) { + LOG_USE_MODULE(libSceNgs2); + LOG_INFO(L"voiceControl_voice id:%u type:%u", phead->id & 0xFFFF, voh->type); + if (voh->type != SceNgs2HandleType::Voice) return Err::Ngs2::INVALID_VOICE_HANDLE; auto voice = (SceNgs2Handle_voice*)voh; @@ -51,12 +54,15 @@ int32_t voiceControl_voice(SceNgs2Handle* voh, const SceNgs2VoiceParamHead* phea case SceNgs2VoiceParam::SET_MATRIX_LEVELS: { } break; case SceNgs2VoiceParam::SET_PORT_VOLUME: { + // todo } break; case SceNgs2VoiceParam::SET_PORT_MATRIX: { } break; case SceNgs2VoiceParam::SET_PORT_DELAY: { } break; case SceNgs2VoiceParam::PATCH: { + auto item = (SceNgs2VoicePatchParam*)phead; + // todo } break; case SceNgs2VoiceParam::KICK_EVENT: { auto item = (SceNgs2VoiceEventParam*)phead; @@ -69,6 +75,9 @@ int32_t voiceControl_voice(SceNgs2Handle* voh, const SceNgs2VoiceParamHead* phea } int32_t voiceControl_mastering(SceNgs2Handle* voh, const SceNgs2VoiceParamHead* phead) { + LOG_USE_MODULE(libSceNgs2); + LOG_INFO(L"voiceControl_mastering id:%u type:%u", phead->id & 0xFFFF, voh->type); + switch ((SceNgs2MasteringParam)(phead->id & 0xFFFF)) { case SceNgs2MasteringParam::SETUP: { } break; @@ -131,6 +140,7 @@ int32_t voiceControl_sampler(SceNgs2Handle* voh, const SceNgs2VoiceParamHead* ph case SceNgs2SamplerParam::SET_FILTER: { } break; } + return Ok; } @@ -198,7 +208,7 @@ EXPORT SYSV_ABI int32_t sceNgs2RackQueryBufferSize(uint32_t rackId, const SceNgs 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) + (numVoices * sizeof(SceNgs2Handle_voice)); + cbi->hostBufferSize = sizeof(SceNgs2Handle_rack); return Ok; } @@ -266,18 +276,6 @@ EXPORT SYSV_ABI int32_t sceNgs2RackCreate(SceNgs2Handle* sysh, uint32_t rackId, auto rack = (SceNgs2Handle_rack*)(*outh); - // Init voices - { - auto addrVoices = (uint64_t)rack + sizeof(SceNgs2Handle_rack); // At end of rack struct - - rack->voices = (SceNgs2Handle_voice*)addrVoices; - - for (uint16_t n = 0; n < rack->options.maxVoices; ++n, addrVoices += sizeof(SceNgs2Handle_voice)) { - auto pVoice = new ((void*)addrVoices) SceNgs2Handle_voice(rack); - } - } - // - - // Add to system if (rackId == SCE_NGS2_RACK_ID_MASTERING || rackId == SCE_NGS2_RACK_ID_CUSTOM_MASTERING) { system->mastering = rack; @@ -307,11 +305,9 @@ EXPORT SYSV_ABI int32_t sceNgs2RackCreateWithAllocator(SceNgs2Handle* sysh, uint auto system = (SceNgs2Handle_system*)sysh; - auto const numVoices = ro != nullptr ? ro->maxVoices : SceNgs2RackOption().maxVoices; - SceNgs2ContextBufferInfo cbi = { .hostBuffer = nullptr, - .hostBufferSize = sizeof(SceNgs2Handle_rack) + (numVoices * sizeof(SceNgs2Handle_voice)), + .hostBufferSize = sizeof(SceNgs2Handle_rack), .userData = alloc->userData, }; @@ -324,17 +320,6 @@ EXPORT SYSV_ABI int32_t sceNgs2RackCreateWithAllocator(SceNgs2Handle* sysh, uint getPimpl()->handles.emplace(*outh); auto rack = (SceNgs2Handle_rack*)(*outh); - // Init voices - { - auto addrVoices = (uint64_t)rack + sizeof(SceNgs2Handle_rack); // At end of rack struct - - rack->voices = (SceNgs2Handle_voice*)addrVoices; - - for (uint16_t n = 0; n < numVoices; ++n, addrVoices += sizeof(SceNgs2Handle_voice)) { - auto pVoice = new ((void*)addrVoices) SceNgs2Handle_voice(rack); - } - } - // - // Add to system if (rackId == SCE_NGS2_RACK_ID_MASTERING || rackId == SCE_NGS2_RACK_ID_CUSTOM_MASTERING) { @@ -399,7 +384,7 @@ EXPORT SYSV_ABI int32_t sceNgs2ParseWaveformData(const void* ptr, size_t size, S boost::unique_lock lock(MUTEX_INT); userData_inerBuffer userData {ptr, size, 0}; - return parseWave(readFunc_linearBuffer, seekFunc_linearBuffer, &userData, wf); + return parseRiffWave(readFunc_linearBuffer, seekFunc_linearBuffer, &userData, wf); } /** @@ -422,7 +407,7 @@ EXPORT SYSV_ABI int32_t sceNgs2ParseWaveformFile(const char* path, long offset, if (fileHandle < 0) return Err::Ngs2::INVALID_WAVEFORM_DATA; if (offset != 0) filesystem::lseek(fileHandle, offset, (int)SceWhence::beg); - return parseWave(readFunc_file, seekFunc_file, reinterpret_cast(fileHandle), wf); + return parseRiffWave(readFunc_file, seekFunc_file, reinterpret_cast(fileHandle), wf); } /** @@ -441,7 +426,7 @@ EXPORT SYSV_ABI int32_t sceNgs2ParseWaveformUser(SceWaveformUserFunc func, uintp boost::unique_lock lock(MUTEX_INT); userData_user userData {func, userData_, 0}; - return parseWave(readFunc_user, seekFunc_user, (void*)&userData, wf); + return parseRiffWave(readFunc_user, seekFunc_user, (void*)&userData, wf); } // - wave parsing @@ -501,9 +486,9 @@ EXPORT SYSV_ABI int32_t sceNgs2RackGetVoiceHandle(SceNgs2Handle* rh, uint32_t vo auto rack = (SceNgs2Handle_rack*)rh; if (voiceId > rack->options.maxVoices) return Err::Ngs2::INVALID_VOICE_INDEX; - *outh = (SceNgs2Handle*)((uint64_t)rack->voices + voiceId * sizeof(SceNgs2Handle_voice)); - getPimpl()->handles.emplace(*outh); + *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; } @@ -562,10 +547,8 @@ EXPORT SYSV_ABI int32_t sceNgs2SystemUnlock(SceNgs2Handle* sysh) { } EXPORT SYSV_ABI int32_t sceNgs2SystemRender(SceNgs2Handle* sysh, SceNgs2RenderBufferInfo* rbi, int32_t count) { - LOG_USE_MODULE(libSceNgs2); - LOG_TRACE(L"todo %S", __FUNCTION__); - - auto system = (SceNgs2Handle_system*)sysh; + boost::unique_lock lock(MUTEX_INT); + auto system = (SceNgs2Handle_system*)sysh; if (system == nullptr) return Err::Ngs2::INVALID_SYSTEM_HANDLE; if (rbi->bufferPtr == nullptr) return Err::Ngs2::INVALID_BUFFER_ADDRESS; if (rbi->bufferSize == 0) return Err::Ngs2::INVALID_BUFFER_SIZE; @@ -583,11 +566,11 @@ EXPORT SYSV_ABI int32_t sceNgs2SystemRender(SceNgs2Handle* sysh, SceNgs2RenderBu } else { for (int32_t i = 0; i < count; i++) { if (rbi[i].bufferPtr != nullptr) { - auto& samplerVoice = system->sampler->voices[0]; - if (samplerVoice.reader != nullptr) { - samplerVoice.reader->getAudio(&samplerVoice, rbi[i].bufferPtr, rbi[i].bufferSize); - } else { - std::memset(rbi[i].bufferPtr, 0, rbi[i].bufferSize); + 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].bufferPtr, rbi[i].bufferSize); + } } } } @@ -672,9 +655,9 @@ EXPORT SYSV_ABI int32_t sceNgs2VoiceGetState(SceNgs2Handle* voh, SceNgs2VoiceSta if (voh->type != SceNgs2HandleType::Voice) return Err::Ngs2::INVALID_VOICE_HANDLE; auto voice = (SceNgs2Handle_voice*)voh; - state->stateFlags = 0x20; // voice->state.data; + state->stateFlags = voice->state.data; - LOG_DEBUG(L"state voice:0x%08llx state:%x", (uint64_t)voh, state->stateFlags); + // LOG_DEBUG(L"state voice:0x%08llx state:%x", (uint64_t)voh, state->stateFlags); return Ok; } @@ -689,9 +672,9 @@ EXPORT SYSV_ABI int32_t sceNgs2VoiceGetStateFlags(SceNgs2Handle* voh, uint32_t* if (voh->type != SceNgs2HandleType::Voice) return Err::Ngs2::INVALID_VOICE_HANDLE; auto voice = (SceNgs2Handle_voice*)voh; - *flags = 0x20; // voice->state.data; + *flags = voice->state.data; - LOG_DEBUG(L"state voice:0x%08llx state:%x", (uint64_t)voh, *flags); + // LOG_DEBUG(L"state voice:0x%08llx state:%x", (uint64_t)voh, *flags); return Ok; } @@ -729,16 +712,15 @@ EXPORT SYSV_ABI int32_t sceNgs2RackDestroy(SceNgs2Handle* rh, SceNgs2ContextBuff int32_t ret = Ok; - for (size_t n = 0; n < rack->options.maxVoices; ++n) { - getPimpl()->handles.erase(&rack->voices[n]); - rack->voices[n].~SceNgs2Handle_voice(); + for (auto voice: rack->voices) { + getPimpl()->handles.erase(&voice.second); } getPimpl()->handles.erase(rh); if (freeHandler != nullptr) { SceNgs2ContextBufferInfo cbi = { .hostBuffer = rack, - .hostBufferSize = sizeof(SceNgs2Handle_rack) + (rack->options.maxVoices * sizeof(SceNgs2Handle_voice)), + .hostBufferSize = sizeof(SceNgs2Handle_rack), }; rack->~SceNgs2Handle_rack(); ret = freeHandler(&cbi); diff --git a/modules/libSceNgs2/readFuncs.cpp b/modules/libSceNgs2/readFuncs.cpp index a579ec3..f7a5284 100644 --- a/modules/libSceNgs2/readFuncs.cpp +++ b/modules/libSceNgs2/readFuncs.cpp @@ -3,12 +3,14 @@ #include "core/fileManager/ifile.h" #include "core/kernel/filesystem.h" #include "logging.h" +#include "riffTypes.h" extern "C" { #include #include } #include #include +#include LOG_DEFINE_MODULE(libSceNgs2); @@ -46,30 +48,37 @@ static SceNgs2WaveFormType convWaveType(AVCodecID codec) { int readFunc_linearBuffer(void* userData_, uint8_t* buf, int size) { auto userData = (userData_inerBuffer*)userData_; - int const dataLeft = userData->size - userData->curOffset; - auto readSize = std::min(dataLeft, size); + int64_t const dataLeft = (int64_t)userData->size - (int64_t)userData->curOffset; + + auto readSize = std::min(dataLeft, (int64_t)size); if (readSize > 0) { + ::memcpy(buf, (uint8_t*)userData->ptr + userData->curOffset, readSize); userData->curOffset += readSize; - ::memcpy(buf, userData->ptr, readSize); return readSize; } + userData->curOffset = 0; // reset it return -1; } int64_t seekFunc_linearBuffer(void* userData_, int64_t offset, int whence) { auto userData = (userData_inerBuffer*)userData_; - switch ((SceWhence)whence) { - case SceWhence::beg: userData->curOffset = offset; break; - case SceWhence::cur: + if ((whence & AVSEEK_SIZE) > 0) { + // return size (0 on not avail) + return userData->size; + } + + switch ((std::ios_base::seekdir)(whence & 0xff)) { + case std::ios_base::beg: userData->curOffset = offset; break; + case std::ios_base::cur: if (userData->curOffset < offset) userData->curOffset = 0; else userData->curOffset += offset; break; - case SceWhence::end: userData->curOffset = std::min(userData->size, userData->size + offset); break; + case std::ios_base::end: userData->curOffset = std::min(userData->size, userData->size + offset); break; } return userData->curOffset; @@ -99,72 +108,88 @@ int64_t seekFunc_user(void* userData_, int64_t offset, int whence) { return 0; // undefined } -int32_t parseWave(funcReadBuf_t readFunc, funcSeekBuf_t seekFunc, void* userData, SceNgs2WaveformFormat* wf) { +int32_t parseRiffWave(funcReadBuf_t readFunc, funcSeekBuf_t seekFunc, void* userData, SceNgs2WaveformFormat* wf) { LOG_USE_MODULE(libSceNgs2); - std::list> cleanup; + // Load headers and check magic - // Setup - auto aBufferIo = (uint8_t*)av_malloc(4096 + AV_INPUT_BUFFER_PADDING_SIZE); - - AVIOContext* avioctx = avio_alloc_context(aBufferIo, 4096, 0, userData, readFunc, nullptr, seekFunc); - - cleanup.emplace_back([&] { av_free(avioctx); }); - cleanup.emplace_back([&] { av_free(aBufferIo); }); - - // Open the input - AVFormatContext* fmtctx = avformat_alloc_context(); - cleanup.emplace_back([&] { avformat_free_context(fmtctx); }); - - fmtctx->pb = avioctx; - fmtctx->flags |= AVFMT_FLAG_CUSTOM_IO; - - int ret = avformat_open_input(&fmtctx, "nullptr", nullptr, nullptr); - if (ret != 0) { - LOG_ERR(L"ParseRIFF: ffmpeg failed to read passed data: %d", ret); + // 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; } - cleanup.emplace_back([&] { avformat_close_input(&fmtctx); }); + // - - AVStream* astream = nullptr; - AVCodec const* codec = nullptr; + // Format header + RiffFormatHeader formatHeader; + readFunc(userData, (uint8_t*)&formatHeader, sizeof(RiffFormatHeader)); - { - auto stream_idx = av_find_best_stream(fmtctx, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0); - - if (stream_idx < 0) { - LOG_ERR(L"ParseRIFF: no audio stream"); - return Err::Ngs2::FAIL; - } - - astream = fmtctx->streams[stream_idx]; + if (memcmp(formatHeader.chunkID, "fmt ", 4) != 0) { + return Err::Ngs2::FAIL; } - auto const totalSize = fmtctx->duration / (fmtctx->bit_rate / 8); + if ((8 + formatHeader.chunkSize) > sizeof(RiffFormatHeader)) { + std::vector 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 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 = convWaveType(astream->codecpar->codec_id); - wf->info.sampleRate = astream->codecpar->sample_rate; - wf->info.channelsCount = convChanCount(astream->codecpar->ch_layout.nb_channels); + 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 - // These are unknown for now - wf->loopBeginPos = 0; - wf->loopEndPos = totalSize; + 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 - wf->samplesCount = (uint64_t)((fmtctx->duration / (float)AV_TIME_BASE) * (float)wf->info.sampleRate * (float)wf->info.channelsCount); + auto& block = wf->block[0]; + block.offset = wf->offset; + block.size = dataSize; + block.numRepeat = 1; + block.skipSamples = 1; + block.numSamples = numOfSamples; + wf->numBlocks = 1; - wf->offset = 0; - wf->size = totalSize; - - wf->frameSize = astream->codecpar->frame_size; - wf->numframeSamples = astream->nb_frames; - wf->samplesDelay = 0; // todo - - auto& block = wf->block[0]; - block.offset = 0; - block.size = totalSize; - wf->numBlocks = 1; - - LOG_DEBUG(L"parse size:0x%08llx", totalSize); return Ok; } \ No newline at end of file diff --git a/modules/libSceNgs2/readFuncs.h b/modules/libSceNgs2/readFuncs.h index 918b411..1aeed42 100644 --- a/modules/libSceNgs2/readFuncs.h +++ b/modules/libSceNgs2/readFuncs.h @@ -23,4 +23,4 @@ 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 parseWave(funcReadBuf_t readFunc, funcSeekBuf_t seekFunc, void* userData, SceNgs2WaveformFormat* wf); \ No newline at end of file +int32_t parseRiffWave(funcReadBuf_t readFunc, funcSeekBuf_t seekFunc, void* userData, SceNgs2WaveformFormat* wf); \ No newline at end of file diff --git a/modules/libSceNgs2/reader.cpp b/modules/libSceNgs2/reader.cpp index 208e1a4..5e90bb2 100644 --- a/modules/libSceNgs2/reader.cpp +++ b/modules/libSceNgs2/reader.cpp @@ -8,6 +8,7 @@ extern "C" { #include "logging.h" #include "readFuncs.h" +#include "riffTypes.h" #include "types.h" #include @@ -19,25 +20,28 @@ namespace { struct PImpl { std::list> cleanup; - userData_inerBuffer userData = {}; + uint8_t const* data = nullptr; + SceNgs2WaveformBlock block; - int64_t numSamples = 0; + uint32_t curOffset = 0; - // AVFormatContext* fmtctx = nullptr; - // AVStream* astream = nullptr; - AVCodec const* codec = nullptr; - int stream_idx = 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; + AVFrame* frame = nullptr; + AVPacket* packet = nullptr; + bool newPacket = true; - // SwrContext* swrCtx = nullptr; + SwrContext* swrCtx = nullptr; }; } // namespace -Reader::Reader() { +Reader::Reader(SceNgs2Handle_voice* parent): parent(parent) { m_pimpl = std::make_unique().release(); } @@ -50,142 +54,210 @@ bool Reader::init(SceNgs2SamplerVoiceWaveformBlocksParam const* param) { auto pimpl = (PImpl*)m_pimpl; + if (param->data == nullptr) { + // Reset + parent->state.bits.Empty = true; + + delete pimpl; + m_pimpl = std::make_unique().release(); + return true; + } + + pimpl->data = (uint8_t const*)param->data; + pimpl->block = param->aBlock[0]; + pimpl->curOffset = 0; + + // 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); + 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); + 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); }); + cleanup->emplace_back([&] { av_free(avioctx); }); + cleanup->emplace_back([&] { av_free(aBufferIo); }); - // // Open the input - // pimpl->fmtctx = avformat_alloc_context(); - // cleanup.emplace_back([&] { avformat_free_context(pimpl->fmtctx); }); + // Open the input + pimpl->fmtctx = avformat_alloc_context(); - // pimpl->fmtctx->pb = avioctx; - // pimpl->fmtctx->flags |= AVFMT_FLAG_CUSTOM_IO; + pimpl->fmtctx->pb = avioctx; + pimpl->fmtctx->flags |= AVFMT_FLAG_CUSTOM_IO; - // int ret = avformat_open_input(&pimpl->fmtctx, "nullptr", 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); }); + int ret = avformat_open_input(&pimpl->fmtctx, "nullptr", 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); }); - // pimpl->stream_idx = av_find_best_stream(pimpl->fmtctx, AVMEDIA_TYPE_AUDIO, -1, -1, &pimpl->codec, 0); + 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; + } - // if (pimpl->stream_idx < 0) { - // LOG_ERR(L"Reader: no audio stream"); - // return false; - // } + pimpl->astream = pimpl->fmtctx->streams[pimpl->stream_idx]; - // pimpl->astream = pimpl->fmtctx->streams[pimpl->stream_idx]; + 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); }); + 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 - // // - + // 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; - // } + if (auto err = avcodec_open2(pimpl->codecContext, pimpl->codec, NULL); err < 0) { + LOG_ERR(L"Reader: avcodec_open2 err:%d", err); + return false; + } - // if (swr_alloc_set_opts2(&pimpl->swrCtx, &pimpl->codecContext->ch_layout, AVSampleFormat::AV_SAMPLE_FMT_S16, pimpl->codecContext->sample_rate, - // &pimpl->codecContext->ch_layout, pimpl->codecContext->sample_fmt, pimpl->codecContext->sample_rate, 0, NULL)) { - // LOG_ERR(L"Reader:Couldn't alloc swr"); - // return false; - // } + AVChannelLayout dstChLayout = AV_CHANNEL_LAYOUT_7POINT1; + if (swr_alloc_set_opts2(&pimpl->swrCtx, &dstChLayout, AVSampleFormat::AV_SAMPLE_FMT_FLT, parent->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); - // cleanup.emplace_back([&] { swr_free(&pimpl->swrCtx); }); + swr_init(pimpl->swrCtx); + cleanup->emplace_back([&] { swr_free(&pimpl->swrCtx); }); - // pimpl->frame = av_frame_alloc(); - // cleanup.emplace_back([&] { av_frame_free(&pimpl->frame); }); + 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); }); + pimpl->packet = av_packet_alloc(); + cleanup->emplace_back([&] { av_packet_free(&pimpl->packet); }); - m_isInit = true; + m_isInit = true; + parent->state.bits.Empty = false; + return true; +} + +bool Reader::getAudioUncompressed(void* buffer, size_t bufferSize) { + auto pimpl = (PImpl*)m_pimpl; + + // Check repeat + if (pimpl->block.size <= pimpl->curOffset) { + if (pimpl->block.numRepeat > 0) { + pimpl->curOffset = 0; + --pimpl->block.numRepeat; + } else { + parent->state.bits.Empty = true; + return false; + } + } + // - + + uint32_t const readSize = std::min(bufferSize, (size_t)pimpl->block.size - pimpl->curOffset); + + std::memcpy(buffer, pimpl->data + pimpl->curOffset, readSize); + pimpl->curOffset += readSize; return true; } -bool Reader::getAudio(SceNgs2Handle_voice* handle, void* buffer, size_t bufferSize) { - if (m_isInit == false || !handle->state.bits.Playing || (handle->state.bits.Playing && handle->state.bits.Paused)) { - std::memset(buffer, 0, bufferSize); - return true; - } +bool Reader::getAudioCompressed(void* buffer, size_t bufferSize) { LOG_USE_MODULE(libSceNgs2); auto pimpl = (PImpl*)m_pimpl; - std::memset(buffer, 0, bufferSize); + size_t offset = 0; - // size_t offset = 0; + while (offset < bufferSize) { + // Get a new packet + if (pimpl->newPacket) { + pimpl->packet->dts = AV_NOPTS_VALUE; + pimpl->packet->pts = AV_NOPTS_VALUE; - // int const outNumSamples = swr_get_out_samples(pimpl->swrCtx, pimpl->frame->nb_samples); - // auto const bufferSize_ = pimpl->frame->ch_layout.nb_channels * outNumSamples * av_get_bytes_per_sample((AVSampleFormat)pimpl->frame->format); + int state = av_read_frame(pimpl->fmtctx, pimpl->packet); - // while (offset < bufferSize) { - // // Get a new packet - // if (pimpl->packet == nullptr) { - // 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 { - // handle->state.bits.Empty = true; - // handle->state.bits.Playing = false; - // } - // std::memset(buffer, 0, bufferSize); - // return false; - // } - // } - // // - + pimpl->newPacket = false; + if (state < 0) { + if (state != AVERROR_EOF) { + LOG_ERR(L"av_read_frame error %d", state); + } else { + parent->state.bits.Empty = true; + parent->state.bits.Playing = false; + } + return 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->packet = nullptr; - // continue; // Get new frame - // } else if (ret == AVERROR_EOF) { - // handle->state.bits.Empty = true; - // } else { - // handle->state.bits.Error = true; - // } - // handle->state.bits.Playing = false; - // std::memset(buffer, 0, bufferSize); - // return 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) { + parent->state.bits.Empty = true; + } else { + parent->state.bits.Error = true; + } + parent->state.bits.Playing = false; - // av_packet_unref(pimpl->packet); - // //- packet + return false; + } - // // Now the frames - // auto const retRecv = avcodec_receive_frame(pimpl->codecContext, pimpl->frame); + av_packet_unref(pimpl->packet); + //- packet - // uint8_t* audioBuffers[1] = {(uint8_t*)buffer + offset}; - // if (swr_convert(pimpl->swrCtx, audioBuffers, outNumSamples, (uint8_t const**)pimpl->frame->extended_data, pimpl->frame->nb_samples) < 0) { - // LOG_WARN(L"swr_convert"); - // } + // Now the frames + auto const retRecv = avcodec_receive_frame(pimpl->codecContext, pimpl->frame); - // av_frame_unref(pimpl->frame); - // // - + int outNumSamples = swr_get_out_samples(pimpl->swrCtx, pimpl->frame->nb_samples); - // offset += bufferSize_; - // } + // todo get sample size, nb_channels is zero (fix) + uint8_t* audioBuffers[1] = {&((uint8_t*)buffer)[offset]}; + if (outNumSamples = swr_convert(pimpl->swrCtx, audioBuffers, 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_ = pimpl->codecContext->ch_layout.nb_channels * outNumSamples * av_get_bytes_per_sample(pimpl->codecContext->sample_fmt); + offset += bufferSize_; + } + return true; +} + +bool Reader::getAudio(void* buffer, size_t bufferSize) { + if (m_isInit == false || !parent->state.bits.Playing || (parent->state.bits.Playing && parent->state.bits.Paused)) { + return true; + } + + if (m_isCompressed) { + return getAudioCompressed(buffer, bufferSize); + } else { + return getAudioUncompressed(buffer, bufferSize); + } return true; } \ No newline at end of file diff --git a/modules/libSceNgs2/reader.h b/modules/libSceNgs2/reader.h index 9841636..b4de198 100644 --- a/modules/libSceNgs2/reader.h +++ b/modules/libSceNgs2/reader.h @@ -5,13 +5,19 @@ struct SceNgs2SamplerVoiceWaveformBlocksParam; class Reader { void* m_pimpl; - bool m_isInit = false; + bool m_isInit = false; + bool m_isCompressed = false; + + SceNgs2Handle_voice* parent; + + bool getAudioUncompressed(void* buffer, size_t bufferSize); + bool getAudioCompressed(void* buffer, size_t bufferSize); public: - Reader(); + Reader(SceNgs2Handle_voice* handle); ~Reader(); bool init(SceNgs2SamplerVoiceWaveformBlocksParam const* param); - bool getAudio(SceNgs2Handle_voice* handle, void* buffer, size_t bufferSize); + bool getAudio(void* buffer, size_t bufferSize); }; \ No newline at end of file diff --git a/modules/libSceNgs2/riffTypes.h b/modules/libSceNgs2/riffTypes.h new file mode 100644 index 0000000..7d4e519 --- /dev/null +++ b/modules/libSceNgs2/riffTypes.h @@ -0,0 +1,24 @@ +#pragma once +#include + +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)); \ No newline at end of file diff --git a/modules/libSceNgs2/types.h b/modules/libSceNgs2/types.h index 712cc01..c81d2b7 100644 --- a/modules/libSceNgs2/types.h +++ b/modules/libSceNgs2/types.h @@ -3,6 +3,7 @@ #include "codes.h" #include "utility/utility.h" +#include #include union SceNgs2VoiceStateFlags { @@ -258,8 +259,9 @@ struct SceNgs2Handle_rack: public SceNgs2Handle { SceNgs2Handle_system* parent; - SceNgs2RackOption options; - SceNgs2Handle_voice* voices; + SceNgs2RackOption options; + + std::map 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) {