Audio: Clean up threading and add AudioStream fadein (RGSS3)
This commit is contained in:
parent
46497eae01
commit
51a0f3903c
|
@ -153,6 +153,7 @@ set(MAIN_HEADERS
|
||||||
src/tileatlasvx.h
|
src/tileatlasvx.h
|
||||||
src/sharedmidistate.h
|
src/sharedmidistate.h
|
||||||
src/fluid-fun.h
|
src/fluid-fun.h
|
||||||
|
src/sdl-util.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(MAIN_SOURCE
|
set(MAIN_SOURCE
|
||||||
|
|
|
@ -11,7 +11,6 @@ Missing RGSS3 functionality:
|
||||||
|
|
||||||
* Text outline
|
* Text outline
|
||||||
* Movie playback
|
* Movie playback
|
||||||
* Audio fade-in
|
|
||||||
|
|
||||||
Some other things might be implemented, but simply not bound yet.
|
Some other things might be implemented, but simply not bound yet.
|
||||||
|
|
||||||
|
|
3
mkxp.pro
3
mkxp.pro
|
@ -131,7 +131,8 @@ HEADERS += \
|
||||||
src/tilemapvx.h \
|
src/tilemapvx.h \
|
||||||
src/tileatlasvx.h \
|
src/tileatlasvx.h \
|
||||||
src/sharedmidistate.h \
|
src/sharedmidistate.h \
|
||||||
src/fluid-fun.h
|
src/fluid-fun.h \
|
||||||
|
src/sdl-util.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
src/main.cpp \
|
src/main.cpp \
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "aldatasource.h"
|
#include "aldatasource.h"
|
||||||
#include "fluid-fun.h"
|
#include "fluid-fun.h"
|
||||||
|
#include "sdl-util.h"
|
||||||
|
|
||||||
#include <SDL_mutex.h>
|
#include <SDL_mutex.h>
|
||||||
#include <SDL_thread.h>
|
#include <SDL_thread.h>
|
||||||
|
@ -38,8 +39,6 @@ ALStream::ALStream(LoopMode loopMode,
|
||||||
source(0),
|
source(0),
|
||||||
thread(0),
|
thread(0),
|
||||||
preemptPause(false),
|
preemptPause(false),
|
||||||
streamInited(false),
|
|
||||||
needsRewind(false),
|
|
||||||
pitch(1.0)
|
pitch(1.0)
|
||||||
{
|
{
|
||||||
alSrc = AL::Source::gen();
|
alSrc = AL::Source::gen();
|
||||||
|
@ -198,7 +197,7 @@ void ALStream::openSource(const std::string &filename)
|
||||||
{
|
{
|
||||||
const char *ext;
|
const char *ext;
|
||||||
shState->fileSystem().openRead(srcOps, filename.c_str(), FileSystem::Audio, false, &ext);
|
shState->fileSystem().openRead(srcOps, filename.c_str(), FileSystem::Audio, false, &ext);
|
||||||
needsRewind = false;
|
needsRewind.clear();
|
||||||
|
|
||||||
/* Try to read ogg file signature */
|
/* Try to read ogg file signature */
|
||||||
char sig[5] = { 0 };
|
char sig[5] = { 0 };
|
||||||
|
@ -227,13 +226,13 @@ void ALStream::openSource(const std::string &filename)
|
||||||
|
|
||||||
void ALStream::stopStream()
|
void ALStream::stopStream()
|
||||||
{
|
{
|
||||||
threadTermReq = true;
|
threadTermReq.set();
|
||||||
|
|
||||||
if (thread)
|
if (thread)
|
||||||
{
|
{
|
||||||
SDL_WaitThread(thread, 0);
|
SDL_WaitThread(thread, 0);
|
||||||
thread = 0;
|
thread = 0;
|
||||||
needsRewind = true;
|
needsRewind.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Need to stop the source _after_ the thread has terminated,
|
/* Need to stop the source _after_ the thread has terminated,
|
||||||
|
@ -249,14 +248,15 @@ void ALStream::startStream(float offset)
|
||||||
AL::Source::clearQueue(alSrc);
|
AL::Source::clearQueue(alSrc);
|
||||||
|
|
||||||
preemptPause = false;
|
preemptPause = false;
|
||||||
streamInited = false;
|
streamInited.clear();
|
||||||
sourceExhausted = false;
|
sourceExhausted.clear();
|
||||||
threadTermReq = false;
|
threadTermReq.clear();
|
||||||
|
|
||||||
startOffset = offset;
|
startOffset = offset;
|
||||||
procFrames = offset * source->sampleRate();
|
procFrames = offset * source->sampleRate();
|
||||||
|
|
||||||
thread = SDL_CreateThread(streamDataFun, threadName.c_str(), this);
|
thread = createSDLThread
|
||||||
|
<ALStream, &ALStream::streamData>(this, threadName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ALStream::pauseStream()
|
void ALStream::pauseStream()
|
||||||
|
@ -344,7 +344,7 @@ void ALStream::streamData()
|
||||||
resumeStream();
|
resumeStream();
|
||||||
|
|
||||||
firstBuffer = false;
|
firstBuffer = false;
|
||||||
streamInited = true;
|
streamInited.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (threadTermReq)
|
if (threadTermReq)
|
||||||
|
@ -352,7 +352,7 @@ void ALStream::streamData()
|
||||||
|
|
||||||
if (status == ALDataSource::EndOfStream)
|
if (status == ALDataSource::EndOfStream)
|
||||||
{
|
{
|
||||||
sourceExhausted = true;
|
sourceExhausted.set();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -400,7 +400,7 @@ void ALStream::streamData()
|
||||||
|
|
||||||
if (status == ALDataSource::Error)
|
if (status == ALDataSource::Error)
|
||||||
{
|
{
|
||||||
sourceExhausted = true;
|
sourceExhausted.set();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,7 +419,7 @@ void ALStream::streamData()
|
||||||
lastBuf = buf;
|
lastBuf = buf;
|
||||||
|
|
||||||
if (status == ALDataSource::EndOfStream)
|
if (status == ALDataSource::EndOfStream)
|
||||||
sourceExhausted = true;
|
sourceExhausted.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (threadTermReq)
|
if (threadTermReq)
|
||||||
|
@ -428,10 +428,3 @@ void ALStream::streamData()
|
||||||
SDL_Delay(AUDIO_SLEEP);
|
SDL_Delay(AUDIO_SLEEP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ALStream::streamDataFun(void *_self)
|
|
||||||
{
|
|
||||||
ALStream &self = *static_cast<ALStream*>(_self);
|
|
||||||
self.streamData();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,12 +23,11 @@
|
||||||
#define ALSTREAM_H
|
#define ALSTREAM_H
|
||||||
|
|
||||||
#include "al-util.h"
|
#include "al-util.h"
|
||||||
|
#include "sdl-util.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <SDL_rwops.h>
|
#include <SDL_rwops.h>
|
||||||
|
|
||||||
struct SDL_mutex;
|
|
||||||
struct SDL_thread;
|
|
||||||
struct ALDataSource;
|
struct ALDataSource;
|
||||||
|
|
||||||
#define STREAM_BUFS 3
|
#define STREAM_BUFS 3
|
||||||
|
@ -59,12 +58,12 @@ struct ALStream
|
||||||
/* When this flag isn't set and alSrc is
|
/* When this flag isn't set and alSrc is
|
||||||
* in 'STOPPED' state, stream isn't over
|
* in 'STOPPED' state, stream isn't over
|
||||||
* (it just hasn't started yet) */
|
* (it just hasn't started yet) */
|
||||||
bool streamInited;
|
AtomicFlag streamInited;
|
||||||
bool sourceExhausted;
|
AtomicFlag sourceExhausted;
|
||||||
|
|
||||||
bool threadTermReq;
|
AtomicFlag threadTermReq;
|
||||||
|
|
||||||
bool needsRewind;
|
AtomicFlag needsRewind;
|
||||||
float startOffset;
|
float startOffset;
|
||||||
|
|
||||||
float pitch;
|
float pitch;
|
||||||
|
@ -118,7 +117,6 @@ private:
|
||||||
|
|
||||||
/* thread func */
|
/* thread func */
|
||||||
void streamData();
|
void streamData();
|
||||||
static int streamDataFun(void *);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ALSTREAM_H
|
#endif // ALSTREAM_H
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "soundemitter.h"
|
#include "soundemitter.h"
|
||||||
#include "sharedstate.h"
|
#include "sharedstate.h"
|
||||||
#include "sharedmidistate.h"
|
#include "sharedmidistate.h"
|
||||||
|
#include "sdl-util.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -55,8 +56,7 @@ struct AudioPrivate
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
SDL_Thread *thread;
|
SDL_Thread *thread;
|
||||||
bool active;
|
AtomicFlag termReq;
|
||||||
bool termReq;
|
|
||||||
MeWatchState state;
|
MeWatchState state;
|
||||||
} meWatch;
|
} meWatch;
|
||||||
|
|
||||||
|
@ -66,19 +66,18 @@ struct AudioPrivate
|
||||||
me(ALStream::NotLooped, "me"),
|
me(ALStream::NotLooped, "me"),
|
||||||
se(conf)
|
se(conf)
|
||||||
{
|
{
|
||||||
meWatch.active = false;
|
|
||||||
meWatch.termReq = false;
|
|
||||||
meWatch.state = MeNotPlaying;
|
meWatch.state = MeNotPlaying;
|
||||||
meWatch.thread = SDL_CreateThread(meWatchFun, "audio_mewatch", this);
|
meWatch.thread = createSDLThread
|
||||||
|
<AudioPrivate, &AudioPrivate::meWatchFun>(this, "audio_mewatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
~AudioPrivate()
|
~AudioPrivate()
|
||||||
{
|
{
|
||||||
meWatch.termReq = true;
|
meWatch.termReq.set();
|
||||||
SDL_WaitThread(meWatch.thread, 0);
|
SDL_WaitThread(meWatch.thread, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void meWatchFunInt()
|
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);
|
||||||
|
@ -121,13 +120,13 @@ struct AudioPrivate
|
||||||
|
|
||||||
bgm.lockStream();
|
bgm.lockStream();
|
||||||
|
|
||||||
float vol = bgm.extVolume;
|
float vol = bgm.getVolume(AudioStream::External);
|
||||||
vol -= fadeOutStep;
|
vol -= fadeOutStep;
|
||||||
|
|
||||||
if (vol < 0 || bgm.stream.queryState() != ALStream::Playing)
|
if (vol < 0 || bgm.stream.queryState() != ALStream::Playing)
|
||||||
{
|
{
|
||||||
/* Either BGM has fully faded out, or stopped midway. -> MePlaying */
|
/* Either BGM has fully faded out, or stopped midway. -> MePlaying */
|
||||||
bgm.setExtVolume1(0);
|
bgm.setVolume(AudioStream::External, 0);
|
||||||
bgm.stream.pause();
|
bgm.stream.pause();
|
||||||
meWatch.state = MePlaying;
|
meWatch.state = MePlaying;
|
||||||
bgm.unlockStream();
|
bgm.unlockStream();
|
||||||
|
@ -136,7 +135,7 @@ struct AudioPrivate
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bgm.setExtVolume1(vol);
|
bgm.setVolume(AudioStream::External, vol);
|
||||||
bgm.unlockStream();
|
bgm.unlockStream();
|
||||||
me.unlockStream();
|
me.unlockStream();
|
||||||
|
|
||||||
|
@ -165,7 +164,7 @@ struct AudioPrivate
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* BGM is stopped. -> MeNotPlaying */
|
/* BGM is stopped. -> MeNotPlaying */
|
||||||
bgm.setExtVolume1(1.0);
|
bgm.setVolume(AudioStream::External, 1.0);
|
||||||
|
|
||||||
if (!bgm.noResumeStop)
|
if (!bgm.noResumeStop)
|
||||||
bgm.stream.play();
|
bgm.stream.play();
|
||||||
|
@ -188,7 +187,7 @@ struct AudioPrivate
|
||||||
if (bgm.stream.queryState() == ALStream::Stopped)
|
if (bgm.stream.queryState() == ALStream::Stopped)
|
||||||
{
|
{
|
||||||
/* BGM stopped midway fade in. -> MeNotPlaying */
|
/* BGM stopped midway fade in. -> MeNotPlaying */
|
||||||
bgm.setExtVolume1(1.0);
|
bgm.setVolume(AudioStream::External, 1.0);
|
||||||
meWatch.state = MeNotPlaying;
|
meWatch.state = MeNotPlaying;
|
||||||
bgm.unlockStream();
|
bgm.unlockStream();
|
||||||
|
|
||||||
|
@ -208,7 +207,7 @@ struct AudioPrivate
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
float vol = bgm.extVolume;
|
float vol = bgm.getVolume(AudioStream::External);
|
||||||
vol += fadeInStep;
|
vol += fadeInStep;
|
||||||
|
|
||||||
if (vol >= 1)
|
if (vol >= 1)
|
||||||
|
@ -218,7 +217,7 @@ struct AudioPrivate
|
||||||
meWatch.state = MeNotPlaying;
|
meWatch.state = MeNotPlaying;
|
||||||
}
|
}
|
||||||
|
|
||||||
bgm.setExtVolume1(vol);
|
bgm.setVolume(AudioStream::External, vol);
|
||||||
|
|
||||||
me.unlockStream();
|
me.unlockStream();
|
||||||
bgm.unlockStream();
|
bgm.unlockStream();
|
||||||
|
@ -230,13 +229,6 @@ struct AudioPrivate
|
||||||
SDL_Delay(AUDIO_SLEEP);
|
SDL_Delay(AUDIO_SLEEP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int meWatchFun(void *self)
|
|
||||||
{
|
|
||||||
static_cast<AudioPrivate*>(self)->meWatchFunInt();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Audio::Audio(const Config &conf)
|
Audio::Audio(const Config &conf)
|
||||||
|
|
|
@ -30,19 +30,21 @@
|
||||||
|
|
||||||
AudioStream::AudioStream(ALStream::LoopMode loopMode,
|
AudioStream::AudioStream(ALStream::LoopMode loopMode,
|
||||||
const std::string &threadId)
|
const std::string &threadId)
|
||||||
: baseVolume(1.0),
|
: extPaused(false),
|
||||||
fadeVolume(1.0),
|
|
||||||
extVolume(1.0),
|
|
||||||
extPaused(false),
|
|
||||||
noResumeStop(false),
|
noResumeStop(false),
|
||||||
stream(loopMode, threadId)
|
stream(loopMode, threadId)
|
||||||
{
|
{
|
||||||
current.volume = 1.0;
|
current.volume = 1.0;
|
||||||
current.pitch = 1.0;
|
current.pitch = 1.0;
|
||||||
|
|
||||||
fade.active = false;
|
for (size_t i = 0; i < VolumeTypeCount; ++i)
|
||||||
|
volumes[i] = 1.0;
|
||||||
|
|
||||||
fade.thread = 0;
|
fade.thread = 0;
|
||||||
fade.threadName = std::string("audio_fade (") + threadId + ")";
|
fade.threadName = std::string("audio_fadeout (") + threadId + ")";
|
||||||
|
|
||||||
|
fadeIn.thread = 0;
|
||||||
|
fadeIn.threadName = std::string("audio_fadein (") + threadId + ")";
|
||||||
|
|
||||||
streamMut = SDL_CreateMutex();
|
streamMut = SDL_CreateMutex();
|
||||||
}
|
}
|
||||||
|
@ -51,10 +53,16 @@ AudioStream::~AudioStream()
|
||||||
{
|
{
|
||||||
if (fade.thread)
|
if (fade.thread)
|
||||||
{
|
{
|
||||||
fade.reqTerm = true;
|
fade.reqTerm.set();
|
||||||
SDL_WaitThread(fade.thread, 0);
|
SDL_WaitThread(fade.thread, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fadeIn.thread)
|
||||||
|
{
|
||||||
|
fadeIn.rqTerm.set();
|
||||||
|
SDL_WaitThread(fadeIn.thread, 0);
|
||||||
|
}
|
||||||
|
|
||||||
lockStream();
|
lockStream();
|
||||||
|
|
||||||
stream.stop();
|
stream.stop();
|
||||||
|
@ -70,7 +78,7 @@ void AudioStream::play(const std::string &filename,
|
||||||
int pitch,
|
int pitch,
|
||||||
float offset)
|
float offset)
|
||||||
{
|
{
|
||||||
finiFadeInt();
|
finiFadeOutInt();
|
||||||
|
|
||||||
lockStream();
|
lockStream();
|
||||||
|
|
||||||
|
@ -96,7 +104,7 @@ void AudioStream::play(const std::string &filename,
|
||||||
&& _pitch == current.pitch
|
&& _pitch == current.pitch
|
||||||
&& (sState == ALStream::Playing || sState == ALStream::Paused))
|
&& (sState == ALStream::Playing || sState == ALStream::Paused))
|
||||||
{
|
{
|
||||||
setBaseVolume(_volume);
|
setVolume(Base, _volume);
|
||||||
current.volume = _volume;
|
current.volume = _volume;
|
||||||
unlockStream();
|
unlockStream();
|
||||||
return;
|
return;
|
||||||
|
@ -132,9 +140,15 @@ void AudioStream::play(const std::string &filename,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
setBaseVolume(_volume);
|
setVolume(Base, _volume);
|
||||||
stream.setPitch(_pitch);
|
stream.setPitch(_pitch);
|
||||||
|
|
||||||
|
if (offset > 0)
|
||||||
|
{
|
||||||
|
setVolume(FadeIn, 0);
|
||||||
|
startFadeIn();
|
||||||
|
}
|
||||||
|
|
||||||
current.filename = filename;
|
current.filename = filename;
|
||||||
current.volume = _volume;
|
current.volume = _volume;
|
||||||
current.pitch = _pitch;
|
current.pitch = _pitch;
|
||||||
|
@ -149,7 +163,7 @@ void AudioStream::play(const std::string &filename,
|
||||||
|
|
||||||
void AudioStream::stop()
|
void AudioStream::stop()
|
||||||
{
|
{
|
||||||
finiFadeInt();
|
finiFadeOutInt();
|
||||||
|
|
||||||
lockStream();
|
lockStream();
|
||||||
|
|
||||||
|
@ -190,18 +204,19 @@ void AudioStream::fadeOut(int duration)
|
||||||
|
|
||||||
if (fade.thread)
|
if (fade.thread)
|
||||||
{
|
{
|
||||||
fade.reqFini = true;
|
fade.reqFini.set();
|
||||||
SDL_WaitThread(fade.thread, 0);
|
SDL_WaitThread(fade.thread, 0);
|
||||||
fade.thread = 0;
|
fade.thread = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fade.active = true;
|
fade.active.set();
|
||||||
fade.msStep = (1.0) / duration;
|
fade.msStep = (1.0) / duration;
|
||||||
fade.reqFini = false;
|
fade.reqFini.clear();
|
||||||
fade.reqTerm = false;
|
fade.reqTerm.clear();
|
||||||
fade.startTicks = SDL_GetTicks();
|
fade.startTicks = SDL_GetTicks();
|
||||||
|
|
||||||
fade.thread = SDL_CreateThread(fadeThreadFun, fade.threadName.c_str(), this);
|
fade.thread = createSDLThread
|
||||||
|
<AudioStream, &AudioStream::fadeOutThread>(this, fade.threadName);
|
||||||
|
|
||||||
unlockStream();
|
unlockStream();
|
||||||
}
|
}
|
||||||
|
@ -219,16 +234,15 @@ void AudioStream::unlockStream()
|
||||||
SDL_UnlockMutex(streamMut);
|
SDL_UnlockMutex(streamMut);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioStream::setFadeVolume(float value)
|
void AudioStream::setVolume(VolumeType type, float value)
|
||||||
{
|
{
|
||||||
fadeVolume = value;
|
volumes[type] = value;
|
||||||
updateVolume();
|
updateVolume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioStream::setExtVolume1(float value)
|
float AudioStream::getVolume(VolumeType type)
|
||||||
{
|
{
|
||||||
extVolume = value;
|
return volumes[type];
|
||||||
updateVolume();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float AudioStream::playingOffset()
|
float AudioStream::playingOffset()
|
||||||
|
@ -236,28 +250,47 @@ float AudioStream::playingOffset()
|
||||||
return stream.queryOffset();
|
return stream.queryOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioStream::finiFadeInt()
|
|
||||||
{
|
|
||||||
if (!fade.thread)
|
|
||||||
return;
|
|
||||||
|
|
||||||
fade.reqFini = true;
|
|
||||||
SDL_WaitThread(fade.thread, 0);
|
|
||||||
fade.thread = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioStream::updateVolume()
|
void AudioStream::updateVolume()
|
||||||
{
|
{
|
||||||
stream.setVolume(baseVolume * fadeVolume * extVolume);
|
float vol = 1.0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < VolumeTypeCount; ++i)
|
||||||
|
vol *= volumes[i];
|
||||||
|
|
||||||
|
stream.setVolume(vol);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioStream::setBaseVolume(float value)
|
void AudioStream::finiFadeOutInt()
|
||||||
{
|
{
|
||||||
baseVolume = value;
|
if (fade.thread)
|
||||||
updateVolume();
|
{
|
||||||
|
fade.reqFini.set();
|
||||||
|
SDL_WaitThread(fade.thread, 0);
|
||||||
|
fade.thread = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fadeIn.thread)
|
||||||
|
{
|
||||||
|
fadeIn.rqFini.set();
|
||||||
|
SDL_WaitThread(fadeIn.thread, 0);
|
||||||
|
fadeIn.thread = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioStream::fadeThread()
|
void AudioStream::startFadeIn()
|
||||||
|
{
|
||||||
|
/* Previous fadein should always be terminated in play() */
|
||||||
|
assert(!fadeIn.thread);
|
||||||
|
|
||||||
|
fadeIn.rqFini.clear();
|
||||||
|
fadeIn.rqTerm.clear();
|
||||||
|
fadeIn.startTicks = SDL_GetTicks();
|
||||||
|
|
||||||
|
fadeIn.thread = createSDLThread
|
||||||
|
<AudioStream, &AudioStream::fadeInThread>(this, fadeIn.threadName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioStream::fadeOutThread()
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -273,31 +306,59 @@ void AudioStream::fadeThread()
|
||||||
ALStream::State state = stream.queryState();
|
ALStream::State state = stream.queryState();
|
||||||
|
|
||||||
if (state != ALStream::Playing
|
if (state != ALStream::Playing
|
||||||
|| resVol < 0
|
|| resVol < 0
|
||||||
|| fade.reqFini)
|
|| fade.reqFini)
|
||||||
{
|
{
|
||||||
if (state != ALStream::Paused)
|
if (state != ALStream::Paused)
|
||||||
stream.stop();
|
stream.stop();
|
||||||
|
|
||||||
setFadeVolume(1.0);
|
setVolume(FadeOut, 1.0);
|
||||||
unlockStream();
|
unlockStream();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
setFadeVolume(resVol);
|
setVolume(FadeOut, resVol);
|
||||||
|
|
||||||
unlockStream();
|
unlockStream();
|
||||||
|
|
||||||
SDL_Delay(AUDIO_SLEEP);
|
SDL_Delay(AUDIO_SLEEP);
|
||||||
}
|
}
|
||||||
|
|
||||||
fade.active = false;
|
fade.active.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int AudioStream::fadeThreadFun(void *self)
|
void AudioStream::fadeInThread()
|
||||||
{
|
{
|
||||||
static_cast<AudioStream*>(self)->fadeThread();
|
while (true)
|
||||||
|
{
|
||||||
|
if (fadeIn.rqTerm)
|
||||||
|
break;
|
||||||
|
|
||||||
return 0;
|
lockStream();
|
||||||
|
|
||||||
|
/* Fade in duration is always 1 second */
|
||||||
|
uint32_t cur = SDL_GetTicks() - fadeIn.startTicks;
|
||||||
|
float prog = cur / 1000.0;
|
||||||
|
|
||||||
|
ALStream::State state = stream.queryState();
|
||||||
|
|
||||||
|
if (state != ALStream::Playing
|
||||||
|
|| prog >= 1.0
|
||||||
|
|| fadeIn.rqFini)
|
||||||
|
{
|
||||||
|
setVolume(FadeIn, 1.0);
|
||||||
|
unlockStream();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quadratic increase (not really the same as
|
||||||
|
* in RMVXA, but close enough) */
|
||||||
|
setVolume(FadeIn, prog*prog);
|
||||||
|
|
||||||
|
unlockStream();
|
||||||
|
|
||||||
|
SDL_Delay(AUDIO_SLEEP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,10 @@
|
||||||
|
|
||||||
#include "al-util.h"
|
#include "al-util.h"
|
||||||
#include "alstream.h"
|
#include "alstream.h"
|
||||||
|
#include "sdl-util.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
struct SDL_mutex;
|
|
||||||
struct SDL_Thread;
|
|
||||||
|
|
||||||
struct AudioStream
|
struct AudioStream
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
|
@ -39,17 +37,21 @@ struct AudioStream
|
||||||
float pitch;
|
float pitch;
|
||||||
} current;
|
} current;
|
||||||
|
|
||||||
/* Volume set with 'play()' */
|
/* Volumes set by external threads,
|
||||||
float baseVolume;
|
|
||||||
|
|
||||||
/* Volume set by external threads,
|
|
||||||
* such as for fade-in/out.
|
* such as for fade-in/out.
|
||||||
* Multiplied with intVolume for final
|
* Multiplied together for final
|
||||||
* playback volume.
|
* playback volume. Used with setVolume().
|
||||||
* fadeVolume: used by fade-out thread.
|
* Base is set by play().
|
||||||
* extVolume: used by MeWatch. */
|
* External is used by MeWatch */
|
||||||
float fadeVolume;
|
enum VolumeType
|
||||||
float extVolume;
|
{
|
||||||
|
Base = 0,
|
||||||
|
FadeOut,
|
||||||
|
FadeIn,
|
||||||
|
External,
|
||||||
|
|
||||||
|
VolumeTypeCount
|
||||||
|
};
|
||||||
|
|
||||||
/* Note that 'extPaused' and 'noResumeStop' are
|
/* Note that 'extPaused' and 'noResumeStop' are
|
||||||
* effectively only used with the AudioStream
|
* effectively only used with the AudioStream
|
||||||
|
@ -76,18 +78,19 @@ struct AudioStream
|
||||||
ALStream stream;
|
ALStream stream;
|
||||||
SDL_mutex *streamMut;
|
SDL_mutex *streamMut;
|
||||||
|
|
||||||
|
/* Fade out */
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
/* Fade is in progress */
|
/* Fade out is in progress */
|
||||||
bool active;
|
AtomicFlag active;
|
||||||
|
|
||||||
/* Request fade thread to finish and
|
/* Request fade thread to finish and
|
||||||
* cleanup (like it normally would) */
|
* cleanup (like it normally would) */
|
||||||
bool reqFini;
|
AtomicFlag reqFini;
|
||||||
|
|
||||||
/* Request fade thread to terminate
|
/* Request fade thread to terminate
|
||||||
* immediately */
|
* immediately */
|
||||||
bool reqTerm;
|
AtomicFlag reqTerm;
|
||||||
|
|
||||||
SDL_Thread *thread;
|
SDL_Thread *thread;
|
||||||
std::string threadName;
|
std::string threadName;
|
||||||
|
@ -100,6 +103,18 @@ struct AudioStream
|
||||||
uint32_t startTicks;
|
uint32_t startTicks;
|
||||||
} fade;
|
} fade;
|
||||||
|
|
||||||
|
/* Fade in */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
AtomicFlag rqFini;
|
||||||
|
AtomicFlag rqTerm;
|
||||||
|
|
||||||
|
SDL_Thread *thread;
|
||||||
|
std::string threadName;
|
||||||
|
|
||||||
|
uint32_t startTicks;
|
||||||
|
} fadeIn;
|
||||||
|
|
||||||
AudioStream(ALStream::LoopMode loopMode,
|
AudioStream(ALStream::LoopMode loopMode,
|
||||||
const std::string &threadId);
|
const std::string &threadId);
|
||||||
~AudioStream();
|
~AudioStream();
|
||||||
|
@ -117,19 +132,20 @@ struct AudioStream
|
||||||
void lockStream();
|
void lockStream();
|
||||||
void unlockStream();
|
void unlockStream();
|
||||||
|
|
||||||
void setFadeVolume(float value);
|
void setVolume(VolumeType type, float value);
|
||||||
void setExtVolume1(float value);
|
float getVolume(VolumeType type);
|
||||||
|
|
||||||
float playingOffset();
|
float playingOffset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void finiFadeInt();
|
float volumes[VolumeTypeCount];
|
||||||
|
|
||||||
void updateVolume();
|
void updateVolume();
|
||||||
void setBaseVolume(float value);
|
|
||||||
|
|
||||||
void fadeThread();
|
void finiFadeOutInt();
|
||||||
static int fadeThreadFun(void *);
|
void startFadeIn();
|
||||||
|
|
||||||
|
void fadeOutThread();
|
||||||
|
void fadeInThread();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AUDIOSTREAM_H
|
#endif // AUDIOSTREAM_H
|
||||||
|
|
|
@ -24,47 +24,20 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "etc-internal.h"
|
#include "etc-internal.h"
|
||||||
|
#include "sdl-util.h"
|
||||||
|
|
||||||
#include <SDL_scancode.h>
|
#include <SDL_scancode.h>
|
||||||
#include <SDL_joystick.h>
|
#include <SDL_joystick.h>
|
||||||
#include <SDL_mouse.h>
|
#include <SDL_mouse.h>
|
||||||
#include <SDL_mutex.h>
|
#include <SDL_mutex.h>
|
||||||
#include <SDL_atomic.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct RGSSThreadData;
|
struct RGSSThreadData;
|
||||||
struct SDL_Thread;
|
|
||||||
struct SDL_Window;
|
struct SDL_Window;
|
||||||
|
|
||||||
struct AtomicFlag
|
|
||||||
{
|
|
||||||
AtomicFlag()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void set()
|
|
||||||
{
|
|
||||||
SDL_AtomicSet(&atom, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
SDL_AtomicSet(&atom, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
operator bool() const
|
|
||||||
{
|
|
||||||
return SDL_AtomicGet(&atom);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable SDL_atomic_t atom;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EventThread
|
class EventThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
#ifndef SDLUTIL_H
|
||||||
|
#define SDLUTIL_H
|
||||||
|
|
||||||
|
#include <SDL_atomic.h>
|
||||||
|
#include <SDL_thread.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct AtomicFlag
|
||||||
|
{
|
||||||
|
AtomicFlag()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set()
|
||||||
|
{
|
||||||
|
SDL_AtomicSet(&atom, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
SDL_AtomicSet(&atom, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
return SDL_AtomicGet(&atom);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable SDL_atomic_t atom;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class C, void (C::*func)()>
|
||||||
|
int __sdlThreadFun(void *obj)
|
||||||
|
{
|
||||||
|
(static_cast<C*>(obj)->*func)();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class C, void (C::*func)()>
|
||||||
|
SDL_Thread *createSDLThread(C *obj, const std::string &name = std::string())
|
||||||
|
{
|
||||||
|
return SDL_CreateThread(__sdlThreadFun<C, func>, name.c_str(), obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SDLUTIL_H
|
Loading…
Reference in New Issue