- fixed a few issues with libmpg123 not correctly reporting the sound's length and issues with repeatedly rewinding the song.

This commit is contained in:
Christoph Oelckers 2017-04-25 21:30:11 +02:00
parent f866e0f02f
commit 99579efd0d
7 changed files with 65 additions and 27 deletions

View file

@ -132,7 +132,7 @@ struct SoundDecoder
virtual size_t read(char *buffer, size_t bytes) = 0; virtual size_t read(char *buffer, size_t bytes) = 0;
virtual TArray<char> readAll(); virtual TArray<char> readAll();
virtual bool seek(size_t ms_offset, bool ms) = 0; virtual bool seek(size_t ms_offset, bool ms, bool mayrestart) = 0;
virtual size_t getSampleOffset() = 0; virtual size_t getSampleOffset() = 0;
virtual size_t getSampleLength() { return 0; } virtual size_t getSampleLength() { return 0; }

View file

@ -190,23 +190,38 @@ size_t MPG123Decoder::read(char *buffer, size_t bytes)
return amt; return amt;
} }
bool MPG123Decoder::seek(size_t ms_offset, bool ms) bool MPG123Decoder::seek(size_t ms_offset, bool ms, bool mayrestart)
{ {
int enc, channels; int enc, channels;
long srate; long srate;
if(mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK) if (!mayrestart || ms_offset > 0)
{ {
size_t smp_offset = ms? (size_t)((double)ms_offset / 1000. * srate) : ms_offset; if (mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK)
if(mpg123_seek(MPG123, (off_t)smp_offset, SEEK_SET) >= 0) {
{ size_t smp_offset = ms ? (size_t)((double)ms_offset / 1000. * srate) : ms_offset;
Done = false; if (mpg123_seek(MPG123, (off_t)smp_offset, SEEK_SET) >= 0)
return true; {
} Done = false;
} return true;
return false; }
}
return false;
}
else
{
// Restart the song instead of rewinding. A rewind seems to cause distortion when done repeatedly.
// offset is intentionally ignored here.
if (MPG123)
{
mpg123_close(MPG123);
mpg123_delete(MPG123);
MPG123 = 0;
}
Reader->Seek(0, SEEK_SET);
return open(Reader);
}
} }
size_t MPG123Decoder::getSampleOffset() size_t MPG123Decoder::getSampleOffset()
{ {
return mpg123_tell(MPG123); return mpg123_tell(MPG123);

View file

@ -21,7 +21,7 @@ struct MPG123Decoder : public SoundDecoder
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
virtual size_t read(char *buffer, size_t bytes); virtual size_t read(char *buffer, size_t bytes);
virtual bool seek(size_t ms_offset, bool ms); virtual bool seek(size_t ms_offset, bool ms, bool mayrestart);
virtual size_t getSampleOffset(); virtual size_t getSampleOffset();
virtual size_t getSampleLength(); virtual size_t getSampleLength();

View file

@ -326,16 +326,39 @@ bool SndFileSong::Read(SoundStream *stream, void *vbuff, int ilen, void *userdat
} }
else else
{ {
// This looks a bit more complicated than necessary because libmpg123 will not read the full requested length for the last block in the file.
if (currentpos + framestoread > song->Loop_End) if (currentpos + framestoread > song->Loop_End)
{ {
size_t endblock = (song->Loop_End - currentpos) * song->Channels * 2; size_t endblock = (song->Loop_End - currentpos) * song->Channels * 2;
err = (song->Decoder->read(buff, endblock) != endblock); size_t endlen = song->Decoder->read(buff, endblock);
buff = buff + endblock; if (endlen != 0)
len -= endblock; {
song->Decoder->seek(song->Loop_Start, false); buff = buff + endblock;
len -= endblock;
song->Decoder->seek(song->Loop_Start, false, true);
}
else
{
song->CritSec.Leave();
return false;
}
}
while (len > 0)
{
size_t readlen = song->Decoder->read(buff, len);
if (readlen == 0)
{
song->CritSec.Leave();
return false;
}
buff += readlen;
len -= readlen;
if (len > 0)
{
song->Decoder->seek(song->Loop_Start, false, true);
}
} }
err |= song->Decoder->read(buff, len) != len;
} }
song->CritSec.Leave(); song->CritSec.Leave();
return !err; return true;
} }

View file

@ -215,7 +215,7 @@ class OpenALSoundStream : public SoundStream
size_t got = self->Decoder->read((char*)ptr, length); size_t got = self->Decoder->read((char*)ptr, length);
if(got < (unsigned int)length) if(got < (unsigned int)length)
{ {
if(!self->Looping || !self->Decoder->seek(0, false)) if(!self->Looping || !self->Decoder->seek(0, false, true))
return false; return false;
got += self->Decoder->read((char*)ptr+got, length-got); got += self->Decoder->read((char*)ptr+got, length-got);
} }
@ -364,7 +364,7 @@ public:
virtual bool SetPosition(unsigned int ms_pos) virtual bool SetPosition(unsigned int ms_pos)
{ {
std::unique_lock<std::mutex> lock(Renderer->StreamLock); std::unique_lock<std::mutex> lock(Renderer->StreamLock);
if(!Decoder->seek(ms_pos, true)) if(!Decoder->seek(ms_pos, true, false))
return false; return false;
if(!Playing.load()) if(!Playing.load())

View file

@ -190,7 +190,7 @@ TArray<char> SndFileDecoder::readAll()
return output; return output;
} }
bool SndFileDecoder::seek(size_t ms_offset, bool ms) bool SndFileDecoder::seek(size_t ms_offset, bool ms, bool /*mayrestart*/)
{ {
size_t smp_offset = ms? (size_t)((double)ms_offset / 1000. * SndInfo.samplerate) : ms_offset; size_t smp_offset = ms? (size_t)((double)ms_offset / 1000. * SndInfo.samplerate) : ms_offset;
if(sf_seek(SndFile, smp_offset, SEEK_SET) < 0) if(sf_seek(SndFile, smp_offset, SEEK_SET) < 0)

View file

@ -17,8 +17,8 @@ struct SndFileDecoder : public SoundDecoder
virtual size_t read(char *buffer, size_t bytes); virtual size_t read(char *buffer, size_t bytes);
virtual TArray<char> readAll(); virtual TArray<char> readAll();
virtual bool seek(size_t ms_offset, bool ms); virtual bool seek(size_t ms_offset, bool ms, bool mayrestart);
virtual size_t getSampleOffset(); virtual size_t getSampleOffset();
virtual size_t getSampleLength(); virtual size_t getSampleLength();
SndFileDecoder() : SndFile(0) { } SndFileDecoder() : SndFile(0) { }