mirror of
https://github.com/SysRay/psOff_public.git
synced 2024-11-23 14:29:39 +00:00
ngs2| dump
This commit is contained in:
parent
980e6f90f0
commit
894a75ad6b
@ -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<int>(port.freq),
|
||||
.freq = static_cast<int>(port.sampleRate),
|
||||
.format = port.sdlFormat,
|
||||
.channels = static_cast<uint8_t>(port.channelsNum),
|
||||
.samples = static_cast<uint16_t>(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<int>(freq),
|
||||
.freq = static_cast<int>(sampleRate),
|
||||
.format = port->sdlFormat,
|
||||
.channels = static_cast<uint8_t>(port->channelsNum),
|
||||
.samples = static_cast<uint16_t>(port->samplesNum),
|
||||
|
@ -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<Reader>().release();
|
||||
if (voice->reader == nullptr) voice->reader = std::make_unique<Reader>(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<void*>(fileHandle), wf);
|
||||
return parseRiffWave(readFunc_file, seekFunc_file, reinterpret_cast<void*>(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);
|
||||
|
@ -3,12 +3,14 @@
|
||||
#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);
|
||||
|
||||
@ -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<std::function<void(void)>> 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<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 = 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;
|
||||
}
|
@ -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);
|
||||
int32_t parseRiffWave(funcReadBuf_t readFunc, funcSeekBuf_t seekFunc, void* userData, SceNgs2WaveformFormat* wf);
|
@ -8,6 +8,7 @@ extern "C" {
|
||||
|
||||
#include "logging.h"
|
||||
#include "readFuncs.h"
|
||||
#include "riffTypes.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <functional>
|
||||
@ -19,25 +20,28 @@ namespace {
|
||||
struct PImpl {
|
||||
std::list<std::function<void(void)>> 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<PImpl>().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<PImpl>().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;
|
||||
}
|
@ -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);
|
||||
};
|
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));
|
@ -3,6 +3,7 @@
|
||||
#include "codes.h"
|
||||
#include "utility/utility.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
union SceNgs2VoiceStateFlags {
|
||||
@ -258,8 +259,9 @@ struct SceNgs2Handle_rack: public SceNgs2Handle {
|
||||
|
||||
SceNgs2Handle_system* parent;
|
||||
|
||||
SceNgs2RackOption options;
|
||||
SceNgs2Handle_voice* voices;
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user