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)
{
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)
@ -569,6 +576,8 @@ struct VorbisSource : ALDataSource
Status retStatus = ALDataSource::NoError;
bool readAgain = false;
if (loop.valid)
{
int tilLoopEnd = loop.end * info.frameSize;
@ -602,7 +611,22 @@ struct VorbisSource : ALDataSource
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;
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));
@ -682,6 +706,7 @@ struct ALStream
bool threadTermReq;
bool needsRewind;
float startOffset;
AL::Source::ID alSrc;
AL::Buffer::ID alBuf[streamBufs];
@ -790,7 +815,7 @@ struct ALStream
state = Stopped;
}
void play()
void play(float offset = 0)
{
checkStopped();
@ -800,7 +825,7 @@ struct ALStream
case Playing:
return;
case Stopped:
startStream();
startStream(offset);
break;
case Paused :
resumeStream();
@ -826,15 +851,6 @@ struct ALStream
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)
{
AL::Source::setVolume(alSrc, value);
@ -907,16 +923,18 @@ private:
procFrames = 0;
}
void startStream()
void startStream(float offset)
{
clearALQueue();
procFrames = 0;
preemptPause = false;
streamInited = false;
sourceExhausted = false;
threadTermReq = false;
startOffset = offset;
procFrames = offset * source->sampleRate();
thread = SDL_CreateThread(streamDataFun, "al_stream", this);
}
@ -988,7 +1006,12 @@ private:
ALDataSource::Status status;
if (needsRewind)
{
if (startOffset > 0)
source->seekToOffset(startOffset);
else
source->reset();
}
for (int i = 0; i < streamBufs; ++i)
{
@ -1177,7 +1200,8 @@ struct AudioStream
void play(const std::string &filename,
int volume,
int pitch)
int pitch,
float offset = 0)
{
finiFadeInt();
@ -1236,7 +1260,7 @@ struct AudioStream
current.pitch = _pitch;
if (!extPaused)
stream.play();
stream.play(offset);
unlockStream();
}
@ -1323,6 +1347,11 @@ struct AudioStream
updateVolume();
}
float playingOffset()
{
return stream.queryOffset();
}
private:
void finiFadeInt()
{
@ -1601,9 +1630,17 @@ Audio::Audio()
void Audio::bgmPlay(const char *filename,
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);
#endif
}
void Audio::bgmStop()
@ -1619,9 +1656,17 @@ void Audio::bgmFade(int time)
void Audio::bgsPlay(const char *filename,
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);
#endif
}
void Audio::bgsStop()
@ -1665,4 +1710,23 @@ void Audio::seStop()
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; }

View File

@ -22,6 +22,16 @@
#ifndef 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;
class Audio
@ -30,21 +40,43 @@ public:
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 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 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 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();
#ifdef RGSS3
void setupMidi();
float bgmPos();
float bgsPos();
#endif
private:
AudioPrivate *p;
};