Add sync audio for emscripten
This commit is contained in:
parent
ee39e65061
commit
9b531afb0c
|
@ -27,7 +27,7 @@
|
||||||
#define DEF_PLAY_STOP(entity) \
|
#define DEF_PLAY_STOP(entity) \
|
||||||
MRB_FUNCTION(audio_##entity##Play) \
|
MRB_FUNCTION(audio_##entity##Play) \
|
||||||
{ \
|
{ \
|
||||||
return mrb_nil_value();char *filename; \
|
char *filename; \
|
||||||
mrb_int volume = 100; \
|
mrb_int volume = 100; \
|
||||||
mrb_int pitch = 100; \
|
mrb_int pitch = 100; \
|
||||||
mrb_get_args(mrb, "z|ii", &filename, &volume, &pitch); \
|
mrb_get_args(mrb, "z|ii", &filename, &volume, &pitch); \
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
} \
|
} \
|
||||||
MRB_FUNCTION(audio_##entity##Stop) \
|
MRB_FUNCTION(audio_##entity##Stop) \
|
||||||
{ \
|
{ \
|
||||||
return mrb_nil_value();MRB_FUN_UNUSED_PARAM; \
|
MRB_FUN_UNUSED_PARAM; \
|
||||||
shState->audio().entity##Stop(); \
|
shState->audio().entity##Stop(); \
|
||||||
return mrb_nil_value(); \
|
return mrb_nil_value(); \
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
#define DEF_FADE(entity) \
|
#define DEF_FADE(entity) \
|
||||||
MRB_FUNCTION(audio_##entity##Fade) \
|
MRB_FUNCTION(audio_##entity##Fade) \
|
||||||
{ \
|
{ \
|
||||||
return mrb_nil_value();mrb_int time; \
|
mrb_int time; \
|
||||||
mrb_get_args(mrb, "i", &time); \
|
mrb_get_args(mrb, "i", &time); \
|
||||||
shState->audio().entity##Fade(time); \
|
shState->audio().entity##Fade(time); \
|
||||||
return mrb_nil_value(); \
|
return mrb_nil_value(); \
|
||||||
|
|
|
@ -19,6 +19,10 @@
|
||||||
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
|
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#include "audio.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
#include "sharedstate.h"
|
#include "sharedstate.h"
|
||||||
#include "binding-util.h"
|
#include "binding-util.h"
|
||||||
|
@ -30,6 +34,10 @@ MRB_FUNCTION(graphicsUpdate)
|
||||||
|
|
||||||
shState->graphics().update();
|
shState->graphics().update();
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
shState->audio().update();
|
||||||
|
#endif
|
||||||
|
|
||||||
return mrb_nil_value();
|
return mrb_nil_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
139
src/alstream.cpp
139
src/alstream.cpp
|
@ -302,8 +302,12 @@ void ALStream::startStream(float offset)
|
||||||
startOffset = offset;
|
startOffset = offset;
|
||||||
procFrames = offset * source->sampleRate();
|
procFrames = offset * source->sampleRate();
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
streamData();
|
||||||
|
#else
|
||||||
thread = createSDLThread
|
thread = createSDLThread
|
||||||
<ALStream, &ALStream::streamData>(this, threadName);
|
<ALStream, &ALStream::streamData>(this, threadName);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ALStream::pauseStream()
|
void ALStream::pauseStream()
|
||||||
|
@ -362,7 +366,6 @@ void ALStream::streamData()
|
||||||
{
|
{
|
||||||
/* Fill up queue */
|
/* Fill up queue */
|
||||||
bool firstBuffer = true;
|
bool firstBuffer = true;
|
||||||
ALDataSource::Status status;
|
|
||||||
|
|
||||||
if (threadTermReq)
|
if (threadTermReq)
|
||||||
return;
|
return;
|
||||||
|
@ -406,74 +409,82 @@ void ALStream::streamData()
|
||||||
|
|
||||||
/* Wait for buffers to be consumed, then
|
/* Wait for buffers to be consumed, then
|
||||||
* refill and queue them up again */
|
* refill and queue them up again */
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
shState->rtData().syncPoint.passSecondarySync();
|
streamDevice();
|
||||||
|
|
||||||
ALint procBufs = AL::Source::getProcBufferCount(alSrc);
|
|
||||||
|
|
||||||
while (procBufs--)
|
|
||||||
{
|
|
||||||
if (threadTermReq)
|
|
||||||
break;
|
|
||||||
|
|
||||||
AL::Buffer::ID buf = AL::Source::unqueueBuffer(alSrc);
|
|
||||||
|
|
||||||
/* If something went wrong, try again later */
|
|
||||||
if (buf == AL::Buffer::ID(0))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (buf == lastBuf)
|
|
||||||
{
|
|
||||||
/* Reset the processed sample count so
|
|
||||||
* querying the playback offset returns 0.0 again */
|
|
||||||
procFrames = source->loopStartFrames();
|
|
||||||
lastBuf = AL::Buffer::ID(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Add the frame count contained in this
|
|
||||||
* buffer to the total count */
|
|
||||||
ALint bits = AL::Buffer::getBits(buf);
|
|
||||||
ALint size = AL::Buffer::getSize(buf);
|
|
||||||
ALint chan = AL::Buffer::getChannels(buf);
|
|
||||||
|
|
||||||
if (bits != 0 && chan != 0)
|
|
||||||
procFrames += ((size / (bits / 8)) / chan);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sourceExhausted)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
status = source->fillBuffer(buf);
|
|
||||||
|
|
||||||
if (status == ALDataSource::Error)
|
|
||||||
{
|
|
||||||
sourceExhausted.set();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AL::Source::queueBuffer(alSrc, buf);
|
|
||||||
|
|
||||||
/* In case of buffer underrun,
|
|
||||||
* start playing again */
|
|
||||||
if (AL::Source::getState(alSrc) == AL_STOPPED)
|
|
||||||
AL::Source::play(alSrc);
|
|
||||||
|
|
||||||
/* If this was the last buffer before the data
|
|
||||||
* source loop wrapped around again, mark it as
|
|
||||||
* such so we can catch it and reset the processed
|
|
||||||
* sample count once it gets unqueued */
|
|
||||||
if (status == ALDataSource::WrapAround)
|
|
||||||
lastBuf = buf;
|
|
||||||
|
|
||||||
if (status == ALDataSource::EndOfStream)
|
|
||||||
sourceExhausted.set();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (threadTermReq)
|
if (threadTermReq)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
SDL_Delay(AUDIO_SLEEP);
|
SDL_Delay(AUDIO_SLEEP);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ALStream::update() {
|
||||||
|
if (threadTermReq)
|
||||||
|
return;
|
||||||
|
|
||||||
|
shState->rtData().syncPoint.passSecondarySync();
|
||||||
|
|
||||||
|
ALint procBufs = AL::Source::getProcBufferCount(alSrc);
|
||||||
|
|
||||||
|
while (procBufs--)
|
||||||
|
{
|
||||||
|
if (threadTermReq)
|
||||||
|
break;
|
||||||
|
|
||||||
|
AL::Buffer::ID buf = AL::Source::unqueueBuffer(alSrc);
|
||||||
|
|
||||||
|
/* If something went wrong, try again later */
|
||||||
|
if (buf == AL::Buffer::ID(0))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (buf == lastBuf)
|
||||||
|
{
|
||||||
|
/* Reset the processed sample count so
|
||||||
|
* querying the playback offset returns 0.0 again */
|
||||||
|
procFrames = source->loopStartFrames();
|
||||||
|
lastBuf = AL::Buffer::ID(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Add the frame count contained in this
|
||||||
|
* buffer to the total count */
|
||||||
|
ALint bits = AL::Buffer::getBits(buf);
|
||||||
|
ALint size = AL::Buffer::getSize(buf);
|
||||||
|
ALint chan = AL::Buffer::getChannels(buf);
|
||||||
|
|
||||||
|
if (bits != 0 && chan != 0)
|
||||||
|
procFrames += ((size / (bits / 8)) / chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceExhausted)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
status = source->fillBuffer(buf);
|
||||||
|
|
||||||
|
if (status == ALDataSource::Error)
|
||||||
|
{
|
||||||
|
sourceExhausted.set();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AL::Source::queueBuffer(alSrc, buf);
|
||||||
|
|
||||||
|
/* In case of buffer underrun,
|
||||||
|
* start playing again */
|
||||||
|
if (AL::Source::getState(alSrc) == AL_STOPPED)
|
||||||
|
AL::Source::play(alSrc);
|
||||||
|
|
||||||
|
/* If this was the last buffer before the data
|
||||||
|
* source loop wrapped around again, mark it as
|
||||||
|
* such so we can catch it and reset the processed
|
||||||
|
* sample count once it gets unqueued */
|
||||||
|
if (status == ALDataSource::WrapAround)
|
||||||
|
lastBuf = buf;
|
||||||
|
|
||||||
|
if (status == ALDataSource::EndOfStream)
|
||||||
|
sourceExhausted.set();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,13 +23,12 @@
|
||||||
#define ALSTREAM_H
|
#define ALSTREAM_H
|
||||||
|
|
||||||
#include "al-util.h"
|
#include "al-util.h"
|
||||||
|
#include "aldatasource.h"
|
||||||
#include "sdl-util.h"
|
#include "sdl-util.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <SDL_rwops.h>
|
#include <SDL_rwops.h>
|
||||||
|
|
||||||
struct ALDataSource;
|
|
||||||
|
|
||||||
#define STREAM_BUFS 3
|
#define STREAM_BUFS 3
|
||||||
|
|
||||||
/* State-machine like audio playback stream.
|
/* State-machine like audio playback stream.
|
||||||
|
@ -104,6 +103,8 @@ struct ALStream
|
||||||
float queryOffset();
|
float queryOffset();
|
||||||
bool queryNativePitch();
|
bool queryNativePitch();
|
||||||
|
|
||||||
|
void update();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void closeSource();
|
void closeSource();
|
||||||
void openSource(const std::string &filename);
|
void openSource(const std::string &filename);
|
||||||
|
@ -117,6 +118,8 @@ private:
|
||||||
|
|
||||||
/* thread func */
|
/* thread func */
|
||||||
void streamData();
|
void streamData();
|
||||||
|
|
||||||
|
ALDataSource::Status status;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ALSTREAM_H
|
#endif // ALSTREAM_H
|
||||||
|
|
|
@ -71,22 +71,27 @@ struct AudioPrivate
|
||||||
syncPoint(rtData.syncPoint)
|
syncPoint(rtData.syncPoint)
|
||||||
{
|
{
|
||||||
meWatch.state = MeNotPlaying;
|
meWatch.state = MeNotPlaying;
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
meWatch.thread = createSDLThread
|
meWatch.thread = createSDLThread
|
||||||
<AudioPrivate, &AudioPrivate::meWatchFun>(this, "audio_mewatch");
|
<AudioPrivate, &AudioPrivate::meWatchFun>(this, "audio_mewatch");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
~AudioPrivate()
|
~AudioPrivate()
|
||||||
{
|
{
|
||||||
meWatch.termReq.set();
|
meWatch.termReq.set();
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
SDL_WaitThread(meWatch.thread, 0);
|
SDL_WaitThread(meWatch.thread, 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void meWatchFun()
|
void meWatchFun()
|
||||||
{
|
{
|
||||||
const float fadeOutStep = 1.f / (200 / AUDIO_SLEEP);
|
const float fadeOutStep = 1.f / (200 / AUDIO_SLEEP);
|
||||||
const float fadeInStep = 1.f / (1000 / AUDIO_SLEEP);
|
const float fadeInStep = 1.f / (1000 / AUDIO_SLEEP);
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
while (true)
|
while (true)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
syncPoint.passSecondarySync();
|
syncPoint.passSecondarySync();
|
||||||
|
|
||||||
|
@ -231,8 +236,9 @@ struct AudioPrivate
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
SDL_Delay(AUDIO_SLEEP);
|
SDL_Delay(AUDIO_SLEEP);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -247,6 +253,7 @@ void Audio::bgmPlay(const char *filename,
|
||||||
int pitch,
|
int pitch,
|
||||||
float pos)
|
float pos)
|
||||||
{
|
{
|
||||||
|
printf("PLAYING BGM %s\n", filename);
|
||||||
p->bgm.play(filename, volume, pitch, pos);
|
p->bgm.play(filename, volume, pitch, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,4 +340,14 @@ void Audio::reset()
|
||||||
p->se.stop();
|
p->se.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Audio::update()
|
||||||
|
{
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
p->bgm.update();
|
||||||
|
p->bgm.update();
|
||||||
|
p->me.update();
|
||||||
|
p->meWatchFun();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
Audio::~Audio() { delete p; }
|
Audio::~Audio() { delete p; }
|
||||||
|
|
|
@ -69,6 +69,8 @@ public:
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
void update();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Audio(RGSSThreadData &rtData);
|
Audio(RGSSThreadData &rtData);
|
||||||
~Audio();
|
~Audio();
|
||||||
|
|
|
@ -203,12 +203,14 @@ void AudioStream::fadeOut(int duration)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
if (fade.thread)
|
if (fade.thread)
|
||||||
{
|
{
|
||||||
fade.reqFini.set();
|
fade.reqFini.set();
|
||||||
SDL_WaitThread(fade.thread, 0);
|
SDL_WaitThread(fade.thread, 0);
|
||||||
fade.thread = 0;
|
fade.thread = 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
fade.active.set();
|
fade.active.set();
|
||||||
fade.msStep = 1.0f / duration;
|
fade.msStep = 1.0f / duration;
|
||||||
|
@ -216,8 +218,10 @@ void AudioStream::fadeOut(int duration)
|
||||||
fade.reqTerm.clear();
|
fade.reqTerm.clear();
|
||||||
fade.startTicks = SDL_GetTicks();
|
fade.startTicks = SDL_GetTicks();
|
||||||
|
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
fade.thread = createSDLThread
|
fade.thread = createSDLThread
|
||||||
<AudioStream, &AudioStream::fadeOutThread>(this, fade.threadName);
|
<AudioStream, &AudioStream::fadeOutThread>(this, fade.threadName);
|
||||||
|
#endif
|
||||||
|
|
||||||
unlockStream();
|
unlockStream();
|
||||||
}
|
}
|
||||||
|
@ -280,24 +284,38 @@ void AudioStream::finiFadeOutInt()
|
||||||
|
|
||||||
void AudioStream::startFadeIn()
|
void AudioStream::startFadeIn()
|
||||||
{
|
{
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
/* Previous fadein should always be terminated in play() */
|
/* Previous fadein should always be terminated in play() */
|
||||||
assert(!fadeIn.thread);
|
assert(!fadeIn.thread);
|
||||||
|
#endif
|
||||||
|
|
||||||
fadeIn.rqFini.clear();
|
fadeIn.rqFini.clear();
|
||||||
fadeIn.rqTerm.clear();
|
fadeIn.rqTerm.clear();
|
||||||
fadeIn.startTicks = SDL_GetTicks();
|
fadeIn.startTicks = SDL_GetTicks();
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
fadeInThread();
|
||||||
|
#else
|
||||||
fadeIn.thread = createSDLThread
|
fadeIn.thread = createSDLThread
|
||||||
<AudioStream, &AudioStream::fadeInThread>(this, fadeIn.threadName);
|
<AudioStream, &AudioStream::fadeInThread>(this, fadeIn.threadName);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioStream::fadeOutThread()
|
void AudioStream::fadeOutThread()
|
||||||
{
|
{
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
while (true)
|
while (true)
|
||||||
|
#else
|
||||||
|
if (fade.active)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
/* Just immediately terminate on request */
|
/* Just immediately terminate on request */
|
||||||
if (fade.reqTerm)
|
if (fade.reqTerm)
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
return;
|
||||||
|
#else
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
lockStream();
|
lockStream();
|
||||||
|
|
||||||
|
@ -315,18 +333,26 @@ void AudioStream::fadeOutThread()
|
||||||
|
|
||||||
setVolume(FadeOut, 1.0f);
|
setVolume(FadeOut, 1.0f);
|
||||||
unlockStream();
|
unlockStream();
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
fade.active.clear();
|
||||||
|
return;
|
||||||
|
#else
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setVolume(FadeOut, resVol);
|
setVolume(FadeOut, resVol);
|
||||||
|
|
||||||
unlockStream();
|
unlockStream();
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
SDL_Delay(AUDIO_SLEEP);
|
SDL_Delay(AUDIO_SLEEP);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
fade.active.clear();
|
fade.active.clear();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioStream::fadeInThread()
|
void AudioStream::fadeInThread()
|
||||||
|
@ -363,3 +389,9 @@ void AudioStream::fadeInThread()
|
||||||
SDL_Delay(AUDIO_SLEEP);
|
SDL_Delay(AUDIO_SLEEP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioStream::update()
|
||||||
|
{
|
||||||
|
fadeOutThread();
|
||||||
|
stream.update();
|
||||||
|
}
|
||||||
|
|
|
@ -140,6 +140,8 @@ struct AudioStream
|
||||||
|
|
||||||
float playingOffset();
|
float playingOffset();
|
||||||
|
|
||||||
|
void update();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float volumes[VolumeTypeCount];
|
float volumes[VolumeTypeCount];
|
||||||
void updateVolume();
|
void updateVolume();
|
||||||
|
|
|
@ -46,6 +46,7 @@ struct SDLSoundSource : ALDataSource
|
||||||
if (!sample)
|
if (!sample)
|
||||||
{
|
{
|
||||||
SDL_RWclose(&ops);
|
SDL_RWclose(&ops);
|
||||||
|
printf("ERROR SDL_sound: %s", Sound_GetError());
|
||||||
throw Exception(Exception::SDLError, "SDL_sound: %s", Sound_GetError());
|
throw Exception(Exception::SDLError, "SDL_sound: %s", Sound_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue