mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-09-10 12:02:53 +02:00
Implement libretro save state serialization/deserialization for audio state
This commit is contained in:
parent
1c83c69f7f
commit
e19ee7f60a
7 changed files with 238 additions and 0 deletions
|
@ -28,6 +28,7 @@
|
|||
#include "eventthread.h"
|
||||
|
||||
#include "mkxp-polyfill.h" // std::to_string
|
||||
#include "wasm-types.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
@ -35,6 +36,7 @@
|
|||
|
||||
#ifdef MKXPZ_RETRO
|
||||
# include "graphics.h"
|
||||
# include "sandbox-serial-util.h"
|
||||
#else
|
||||
# include "sdl-util.h"
|
||||
# include <SDL_mutex.h>
|
||||
|
@ -606,3 +608,41 @@ void Audio::reset()
|
|||
}
|
||||
|
||||
Audio::~Audio() { delete p; }
|
||||
|
||||
bool Audio::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
|
||||
{
|
||||
if (!mkxp_sandbox::sandbox_serialize((mkxp_sandbox::wasm_size_t)p->bgmTracks.size(), data, max_size)) return false;
|
||||
|
||||
for (AudioStream *track : p->bgmTracks) {
|
||||
if (!track->sandbox_serialize(data, max_size)) return false;
|
||||
}
|
||||
|
||||
if (!p->bgs.sandbox_serialize(data, max_size)) return false;
|
||||
|
||||
if (!p->me.sandbox_serialize(data, max_size)) return false;
|
||||
|
||||
if (!p->se.sandbox_serialize(data, max_size)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Audio::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
|
||||
{
|
||||
{
|
||||
mkxp_sandbox::wasm_size_t count;
|
||||
if (!mkxp_sandbox::sandbox_deserialize(count, data, max_size)) return false;
|
||||
if (count != p->bgmTracks.size()) return false;
|
||||
}
|
||||
|
||||
for (AudioStream *track : p->bgmTracks) {
|
||||
if (!track->sandbox_deserialize(data, max_size)) return false;
|
||||
}
|
||||
|
||||
if (!p->bgs.sandbox_deserialize(data, max_size)) return false;
|
||||
|
||||
if (!p->me.sandbox_deserialize(data, max_size)) return false;
|
||||
|
||||
if (!p->se.sandbox_deserialize(data, max_size)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#ifdef MKXPZ_RETRO
|
||||
# include "mkxp-polyfill.h"
|
||||
# include "wasm-types.h"
|
||||
#else
|
||||
# include <SDL_mutex.h>
|
||||
#endif // MKXPZ_RETRO
|
||||
|
@ -124,6 +125,11 @@ public:
|
|||
|
||||
std::string getLastError();
|
||||
|
||||
#ifdef MKXPZ_RETRO
|
||||
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size);
|
||||
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
|
||||
#endif // MKXPZ_RETRO
|
||||
|
||||
#ifndef MKXPZ_RETRO
|
||||
private:
|
||||
#endif // MKXPZ_RETRO
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#ifdef MKXPZ_RETRO
|
||||
# include "core.h"
|
||||
# include "sandbox-serial-util.h"
|
||||
#else
|
||||
# include <SDL_mutex.h>
|
||||
# include <SDL_thread.h>
|
||||
|
@ -435,6 +436,72 @@ void AudioStream::render()
|
|||
|
||||
stream.render();
|
||||
}
|
||||
|
||||
bool AudioStream::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
|
||||
{
|
||||
AudioMutexGuard guard(mutex);
|
||||
|
||||
ALStream::State state = stream.queryState();
|
||||
|
||||
if (!mkxp_sandbox::sandbox_serialize(current.filename, data, max_size)) return false;
|
||||
|
||||
if (!mkxp_sandbox::sandbox_serialize(state, data, max_size)) return false;
|
||||
if (!mkxp_sandbox::sandbox_serialize(playingOffset(), data, max_size)) return false;
|
||||
|
||||
if (!mkxp_sandbox::sandbox_serialize(current.pitch, data, max_size)) return false;
|
||||
|
||||
for (int i = 0; i < AudioStream::VolumeType::VolumeTypeCount; ++i) {
|
||||
if (!mkxp_sandbox::sandbox_serialize(volumes[i], data, max_size)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioStream::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
|
||||
{
|
||||
AudioMutexGuard guard(mutex);
|
||||
{
|
||||
std::string value;
|
||||
if (!mkxp_sandbox::sandbox_deserialize(current.filename, data, max_size)) return false;
|
||||
if (current.filename != value) {
|
||||
Exception e;
|
||||
stream.open(e, current.filename);
|
||||
if (e.is_error()) return false;
|
||||
}
|
||||
}
|
||||
|
||||
ALStream::State state;
|
||||
if (!mkxp_sandbox::sandbox_deserialize(state, data, max_size)) return false;
|
||||
double offset;
|
||||
if (!mkxp_sandbox::sandbox_deserialize(offset, data, max_size)) return false;
|
||||
if (state != stream.queryState()) {
|
||||
stream.stop();
|
||||
switch (state) {
|
||||
case ALStream::State::Playing:
|
||||
stream.needsRewind.set();
|
||||
stream.play(offset);
|
||||
break;
|
||||
case ALStream::State::Paused:
|
||||
stream.needsRewind.set();
|
||||
stream.play(offset);
|
||||
stream.pause();
|
||||
break;
|
||||
case ALStream::State::Stopped:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mkxp_sandbox::sandbox_deserialize(current.pitch, data, max_size)) return false;
|
||||
stream.setPitch(current.pitch);
|
||||
|
||||
for (int i = 0; i < AudioStream::VolumeType::VolumeTypeCount; ++i) {
|
||||
if (!mkxp_sandbox::sandbox_deserialize(volumes[i], data, max_size)) return false;
|
||||
}
|
||||
updateVolume();
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
void AudioStream::fadeOutThread()
|
||||
{
|
||||
|
|
|
@ -29,6 +29,10 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#ifdef MKXPZ_RETRO
|
||||
# include "wasm-types.h"
|
||||
#endif // MKXPZ_RETRO
|
||||
|
||||
struct AudioStream
|
||||
{
|
||||
struct
|
||||
|
@ -152,6 +156,9 @@ struct AudioStream
|
|||
|
||||
#ifdef MKXPZ_RETRO
|
||||
void render();
|
||||
|
||||
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size);
|
||||
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
|
||||
#endif // MKXPZ_RETRO
|
||||
|
||||
private:
|
||||
|
|
|
@ -29,9 +29,11 @@
|
|||
#include "config.h"
|
||||
#include "util.h"
|
||||
#include "debugwriter.h"
|
||||
#include "wasm-types.h"
|
||||
|
||||
#ifdef MKXPZ_RETRO
|
||||
# include <sndfile.hh>
|
||||
# include "sandbox-serial-util.h"
|
||||
#else
|
||||
# include <SDL_sound.h>
|
||||
#endif // MKXPZ_RETRO
|
||||
|
@ -99,6 +101,7 @@ SoundEmitter::SoundEmitter(const Config &conf)
|
|||
srcCount(conf.SE.sourceCount),
|
||||
alSrcs(srcCount),
|
||||
atchBufs(srcCount),
|
||||
filenames(srcCount),
|
||||
srcPrio(srcCount)
|
||||
{
|
||||
for (size_t i = 0; i < srcCount; ++i)
|
||||
|
@ -182,6 +185,8 @@ void SoundEmitter::play(const std::string &filename,
|
|||
AL::Source::setPitch(src, _pitch);
|
||||
|
||||
AL::Source::play(src);
|
||||
|
||||
filenames[srcIndex] = filename;
|
||||
}
|
||||
|
||||
void SoundEmitter::stop()
|
||||
|
@ -336,3 +341,100 @@ SoundBuffer *SoundEmitter::allocateBuffer(const std::string &filename)
|
|||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
bool SoundEmitter::sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size)
|
||||
{
|
||||
if (!mkxp_sandbox::sandbox_serialize((mkxp_sandbox::wasm_size_t)srcCount, data, max_size)) return false;
|
||||
|
||||
for (size_t i = 0; i < srcCount; ++i) {
|
||||
if (!mkxp_sandbox::sandbox_serialize(filenames[i], data, max_size)) return false;
|
||||
|
||||
AL::Source::ID source = alSrcs[i];
|
||||
ALenum state = AL::Source::getState(source);
|
||||
if (!mkxp_sandbox::sandbox_serialize((int32_t)state, data, max_size)) return false;
|
||||
|
||||
{
|
||||
ALfloat value;
|
||||
alGetSourcef(source.al, AL_SEC_OFFSET, &value);
|
||||
if (!mkxp_sandbox::sandbox_serialize(value, data, max_size)) return false;
|
||||
}
|
||||
{
|
||||
ALfloat value;
|
||||
alGetSourcef(source.al, AL_PITCH, &value);
|
||||
if (!mkxp_sandbox::sandbox_serialize(value, data, max_size)) return false;
|
||||
}
|
||||
{
|
||||
ALfloat value;
|
||||
alGetSourcef(source.al, AL_GAIN, &value);
|
||||
if (!mkxp_sandbox::sandbox_serialize(value, data, max_size)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoundEmitter::sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size)
|
||||
{
|
||||
{
|
||||
mkxp_sandbox::wasm_size_t count;
|
||||
if (!mkxp_sandbox::sandbox_deserialize(count, data, max_size)) return false;
|
||||
if (count != srcCount) return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < srcCount; ++i) {
|
||||
AL::Source::ID source = alSrcs[i];
|
||||
|
||||
{
|
||||
std::string value = filenames[i];
|
||||
if (!mkxp_sandbox::sandbox_deserialize(filenames[i], data, max_size)) return false;
|
||||
if (atchBufs[i] != nullptr) {
|
||||
SoundBuffer::deref(atchBufs[i]);
|
||||
}
|
||||
if (filenames[i] != value) {
|
||||
if (filenames[i].empty()) {
|
||||
atchBufs[i] = nullptr;
|
||||
} else {
|
||||
SoundBuffer *buffer = allocateBuffer(filenames[i]);
|
||||
if (buffer == nullptr) return false;
|
||||
atchBufs[i] = SoundBuffer::ref(buffer);
|
||||
AL::Source::attachBuffer(source, buffer->alBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t state;
|
||||
if (!mkxp_sandbox::sandbox_deserialize(state, data, max_size)) return false;
|
||||
if (state != AL::Source::getState(source)) {
|
||||
switch (state) {
|
||||
case AL_PLAYING:
|
||||
AL::Source::play(source);
|
||||
break;
|
||||
case AL_PAUSED:
|
||||
AL::Source::pause(source);
|
||||
break;
|
||||
case AL_STOPPED:
|
||||
default:
|
||||
AL::Source::stop(source);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ALfloat value;
|
||||
if (!mkxp_sandbox::sandbox_deserialize(value, data, max_size)) return false;
|
||||
alSourcef(source.al, AL_SEC_OFFSET, value);
|
||||
}
|
||||
{
|
||||
ALfloat value;
|
||||
if (!mkxp_sandbox::sandbox_deserialize(value, data, max_size)) return false;
|
||||
alSourcef(source.al, AL_PITCH, value);
|
||||
}
|
||||
{
|
||||
ALfloat value;
|
||||
if (!mkxp_sandbox::sandbox_deserialize(value, data, max_size)) return false;
|
||||
alSourcef(source.al, AL_GAIN, value);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,10 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef MKXPZ_RETRO
|
||||
# include "wasm-types.h"
|
||||
#endif // MKXPZ_RETRO
|
||||
|
||||
struct SoundBuffer;
|
||||
struct Config;
|
||||
|
||||
|
@ -45,6 +49,7 @@ struct SoundEmitter
|
|||
const size_t srcCount;
|
||||
std::vector<AL::Source::ID> alSrcs;
|
||||
std::vector<SoundBuffer*> atchBufs;
|
||||
std::vector<std::string> filenames;
|
||||
|
||||
/* Indices of sources, sorted by priority (lowest first) */
|
||||
std::vector<size_t> srcPrio;
|
||||
|
@ -58,6 +63,11 @@ struct SoundEmitter
|
|||
|
||||
void stop();
|
||||
|
||||
#ifdef MKXPZ_RETRO
|
||||
bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size);
|
||||
bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size);
|
||||
#endif // MKXPZ_RETRO
|
||||
|
||||
private:
|
||||
SoundBuffer *allocateBuffer(const std::string &filename);
|
||||
};
|
||||
|
|
|
@ -1732,6 +1732,9 @@ extern "C" RETRO_API bool retro_serialize(void *data, size_t len) {
|
|||
ADVANCE(shState->graphics().frozenPixels.size());
|
||||
}
|
||||
|
||||
// Write the audio state
|
||||
if (!audio->sandbox_serialize(data, max_size)) return false;
|
||||
|
||||
std::memset(data, 0, max_size);
|
||||
return true;
|
||||
}
|
||||
|
@ -2079,6 +2082,9 @@ extern "C" RETRO_API bool retro_unserialize(const void *data, size_t len) {
|
|||
ADVANCE((size_t)shState->graphics().width() * (size_t)shState->graphics().height());
|
||||
}
|
||||
|
||||
// Read the audio state
|
||||
if (!audio->sandbox_deserialize(data, max_size)) DESER_FAIL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue