Audio: Implement RGSS3 functionality

'Pos' and 'Play' functions take a float for
their 'pos' parameter, which is in seconds
of playback.

'setupMidi' is a noop at this point.
This commit is contained in:
Jonas Kulla 2013-12-05 00:24:18 +01:00
parent ef2430e0c3
commit 5fca94616c
2 changed files with 123 additions and 27 deletions

View File

@ -556,7 +556,14 @@ struct VorbisSource : ALDataSource
void seekToOffset(float seconds) void seekToOffset(float seconds)
{ {
ov_time_seek(&vf, seconds); currentFrame = seconds * info.rate;
if (loop.valid && currentFrame > loop.end)
currentFrame = loop.start;
/* If seeking fails, just seek back to start */
if (ov_pcm_seek(&vf, currentFrame) != 0)
ov_raw_seek(&vf, 0);
} }
Status fillBuffer(AL::Buffer::ID alBuffer) Status fillBuffer(AL::Buffer::ID alBuffer)
@ -569,6 +576,8 @@ struct VorbisSource : ALDataSource
Status retStatus = ALDataSource::NoError; Status retStatus = ALDataSource::NoError;
bool readAgain = false;
if (loop.valid) if (loop.valid)
{ {
int tilLoopEnd = loop.end * info.frameSize; int tilLoopEnd = loop.end * info.frameSize;
@ -602,7 +611,22 @@ struct VorbisSource : ALDataSource
retStatus = ALDataSource::EndOfStream; retStatus = ALDataSource::EndOfStream;
} }
/* If we sought right to the end of the file,
* we might be EOF without actually having read
* any data at all yet (which mustn't happen),
* so we try to continue reading some data. */
if (bufUsed > 0)
break; break;
if (readAgain)
{
/* We're still not getting data though.
* Just error out to prevent an endless loop */
retStatus = ALDataSource::Error;
break;
}
readAgain = true;
} }
bufUsed += (res / sizeof(int16_t)); bufUsed += (res / sizeof(int16_t));
@ -682,6 +706,7 @@ struct ALStream
bool threadTermReq; bool threadTermReq;
bool needsRewind; bool needsRewind;
float startOffset;
AL::Source::ID alSrc; AL::Source::ID alSrc;
AL::Buffer::ID alBuf[streamBufs]; AL::Buffer::ID alBuf[streamBufs];
@ -790,7 +815,7 @@ struct ALStream
state = Stopped; state = Stopped;
} }
void play() void play(float offset = 0)
{ {
checkStopped(); checkStopped();
@ -800,7 +825,7 @@ struct ALStream
case Playing: case Playing:
return; return;
case Stopped: case Stopped:
startStream(); startStream(offset);
break; break;
case Paused : case Paused :
resumeStream(); resumeStream();
@ -826,15 +851,6 @@ struct ALStream
state = Paused; state = Paused;
} }
void setOffset(float value)
{
if (state == Closed)
return;
// XXX needs more work. protect source with mutex
source->seekToOffset(value);
needsRewind = false;
}
void setVolume(float value) void setVolume(float value)
{ {
AL::Source::setVolume(alSrc, value); AL::Source::setVolume(alSrc, value);
@ -907,16 +923,18 @@ private:
procFrames = 0; procFrames = 0;
} }
void startStream() void startStream(float offset)
{ {
clearALQueue(); clearALQueue();
procFrames = 0;
preemptPause = false; preemptPause = false;
streamInited = false; streamInited = false;
sourceExhausted = false; sourceExhausted = false;
threadTermReq = false; threadTermReq = false;
startOffset = offset;
procFrames = offset * source->sampleRate();
thread = SDL_CreateThread(streamDataFun, "al_stream", this); thread = SDL_CreateThread(streamDataFun, "al_stream", this);
} }
@ -988,7 +1006,12 @@ private:
ALDataSource::Status status; ALDataSource::Status status;
if (needsRewind) if (needsRewind)
{
if (startOffset > 0)
source->seekToOffset(startOffset);
else
source->reset(); source->reset();
}
for (int i = 0; i < streamBufs; ++i) for (int i = 0; i < streamBufs; ++i)
{ {
@ -1177,7 +1200,8 @@ struct AudioStream
void play(const std::string &filename, void play(const std::string &filename,
int volume, int volume,
int pitch) int pitch,
float offset = 0)
{ {
finiFadeInt(); finiFadeInt();
@ -1236,7 +1260,7 @@ struct AudioStream
current.pitch = _pitch; current.pitch = _pitch;
if (!extPaused) if (!extPaused)
stream.play(); stream.play(offset);
unlockStream(); unlockStream();
} }
@ -1323,6 +1347,11 @@ struct AudioStream
updateVolume(); updateVolume();
} }
float playingOffset()
{
return stream.queryOffset();
}
private: private:
void finiFadeInt() void finiFadeInt()
{ {
@ -1601,9 +1630,17 @@ Audio::Audio()
void Audio::bgmPlay(const char *filename, void Audio::bgmPlay(const char *filename,
int volume, int volume,
int pitch) int pitch
#ifdef RGSS3
,float pos
#endif
)
{ {
#ifdef RGSS3
p->bgm.play(filename, volume, pitch, pos);
#else
p->bgm.play(filename, volume, pitch); p->bgm.play(filename, volume, pitch);
#endif
} }
void Audio::bgmStop() void Audio::bgmStop()
@ -1619,9 +1656,17 @@ void Audio::bgmFade(int time)
void Audio::bgsPlay(const char *filename, void Audio::bgsPlay(const char *filename,
int volume, int volume,
int pitch) int pitch
#ifdef RGSS3
,float pos
#endif
)
{ {
#ifdef RGSS3
p->bgs.play(filename, volume, pitch, pos);
#else
p->bgs.play(filename, volume, pitch); p->bgs.play(filename, volume, pitch);
#endif
} }
void Audio::bgsStop() void Audio::bgsStop()
@ -1665,4 +1710,23 @@ void Audio::seStop()
p->se.stop(); p->se.stop();
} }
#ifdef RGSS3
void Audio::setupMidi()
{
}
float Audio::bgmPos()
{
return p->bgm.playingOffset();
}
float Audio::bgsPos()
{
return p->bgs.playingOffset();
}
#endif
Audio::~Audio() { delete p; } Audio::~Audio() { delete p; }

View File

@ -22,6 +22,16 @@
#ifndef AUDIO_H #ifndef AUDIO_H
#define AUDIO_H #define AUDIO_H
/* Concerning the 'pos' parameter:
* RGSS3 actually doesn't specify a format for this,
* it's only implied that it is a numerical value
* (must be 0 on invalid cases), and it's not used for
* anything outside passing it back into bgm/bgs_play.
* We use this freedom to define pos to be a float,
* in seconds of playback. (RGSS3 seems to use large
* integers that _look_ like sample offsets but I can't
* quite make out their meaning yet) */
struct AudioPrivate; struct AudioPrivate;
class Audio class Audio
@ -30,21 +40,43 @@ public:
Audio(); Audio();
~Audio(); ~Audio();
void bgmPlay(const char *filename, int volume = 100, int pitch = 100); void bgmPlay(const char *filename,
int volume = 100,
int pitch = 100
#ifdef RGSS3
,float pos = 0
#endif
);
void bgmStop(); void bgmStop();
void bgmFade(int time); void bgmFade(int time);
void bgsPlay(const char *filename, int volume = 100, int pitch = 100); void bgsPlay(const char *filename,
int volume = 100,
int pitch = 100
#ifdef RGSS3
,float pos = 0
#endif
);
void bgsStop(); void bgsStop();
void bgsFade(int time); void bgsFade(int time);
void mePlay(const char *filename, int volume = 100, int pitch = 100); void mePlay(const char *filename,
int volume = 100,
int pitch = 100);
void meStop(); void meStop();
void meFade(int time); void meFade(int time);
void sePlay(const char *filename, int volume = 100, int pitch = 100); void sePlay(const char *filename,
int volume = 100,
int pitch = 100);
void seStop(); void seStop();
#ifdef RGSS3
void setupMidi();
float bgmPos();
float bgsPos();
#endif
private: private:
AudioPrivate *p; AudioPrivate *p;
}; };