aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Göffringmann2005-02-21 08:35:18 +0000
committerRobert Göffringmann2005-02-21 08:35:18 +0000
commitc7dad332fa6f8cf3ae88d638cd0c990524966e14 (patch)
treea5e375919180e5fb8bc1c30e319b7a41d2e46c23
parent8edce85e04a75907e668db286818ad868e3feed2 (diff)
downloadscummvm-rg350-c7dad332fa6f8cf3ae88d638cd0c990524966e14.tar.gz
scummvm-rg350-c7dad332fa6f8cf3ae88d638cd0c990524966e14.tar.bz2
scummvm-rg350-c7dad332fa6f8cf3ae88d638cd0c990524966e14.zip
basically the same change as for bs1; don't keep the mutex locked while loading mp3, ogg or wave data. it blocks the playing thread for too long.
Also added index caching for the speech and music clusters to reduce seeks. svn-id: r16849
-rw-r--r--sword2/driver/d_sound.cpp195
-rw-r--r--sword2/sound.cpp23
-rw-r--r--sword2/sound.h18
3 files changed, 143 insertions, 93 deletions
diff --git a/sword2/driver/d_sound.cpp b/sword2/driver/d_sound.cpp
index a8e3d444e0..81890e6fbb 100644
--- a/sword2/driver/d_sound.cpp
+++ b/sword2/driver/d_sound.cpp
@@ -40,95 +40,106 @@ namespace Sword2 {
static AudioStream *makeCLUStream(File *fp, int size);
-static AudioStream *getAudioStream(File *fp, const char *base, int cd, uint32 id, uint32 *numSamples) {
- struct {
- const char *ext;
- int mode;
- } file_types[] = {
-#ifdef USE_MAD
- { "cl3", kMP3Mode },
-#endif
-#ifdef USE_VORBIS
- { "clg", kVorbisMode },
-#endif
-#ifdef USE_FLAC
- { "clf", kFlacMode },
-#endif
- { "clu", kCLUMode }
- };
+static AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, int cd, uint32 id, uint32 *numSamples) {
+ if (!fh->file->isOpen()) {
+ struct {
+ const char *ext;
+ int mode;
+ } file_types[] = {
+ #ifdef USE_MAD
+ { "cl3", kMP3Mode },
+ #endif
+ #ifdef USE_VORBIS
+ { "clg", kVorbisMode },
+ #endif
+ #ifdef USE_FLAC
+ { "clf", kFlacMode },
+ #endif
+ { "clu", kCLUMode }
+ };
+
+ int soundMode = -1;
+ char filename[20];
+
+ for (int i = 0; i < ARRAYSIZE(file_types); i++) {
+ File f;
+
+ sprintf(filename, "%s%d.%s", base, cd, file_types[i].ext);
+ if (f.open(filename)) {
+ soundMode = file_types[i].mode;
+ break;
+ }
- int soundMode = -1;
- char filename[20];
+ sprintf(filename, "%s.%s", base, file_types[i].ext);
+ if (f.open(filename)) {
+ soundMode = file_types[i].mode;
+ break;
+ }
+ }
- for (int i = 0; i < ARRAYSIZE(file_types); i++) {
- File f;
+ if (soundMode == 0)
+ return NULL;
- sprintf(filename, "%s%d.%s", base, cd, file_types[i].ext);
- if (f.open(filename)) {
- soundMode = file_types[i].mode;
- break;
+ fh->file->open(filename);
+ fh->fileType = soundMode;
+ if (!fh->file->isOpen()) {
+ warning("Very strange fopen error");
+ return NULL;
}
-
- sprintf(filename, "%s.%s", base, file_types[i].ext);
- if (f.open(filename)) {
- soundMode = file_types[i].mode;
- break;
+ if (fh->fileSize != fh->file->size()) {
+ if (fh->idxTab) {
+ free(fh->idxTab);
+ fh->idxTab = NULL;
+ }
}
}
- if (soundMode == 0)
- return NULL;
-
- // The assumption here is that a sound file is closed when the sound
- // finishes, and we never play sounds from two different files at the
- // same time. Thus, if the file is already open it's the correct file,
- // and the loop above was just needed to figure out the compression.
- //
- // This is to avoid having two file handles open to the same file at
- // the same time. There was some speculation that some of our target
- // systems may have trouble with that.
+ uint32 entrySize = (fh->fileType == kCLUMode) ? 2 : 3;
- if (!fp->isOpen())
- fp->open(filename);
-
- if (!fp->isOpen())
- return NULL;
+ if (!fh->idxTab) {
+ fh->file->seek(0);
+ fh->idxLen = fh->file->readUint32LE();
+ fh->file->seek(entrySize * 4);
- fp->seek((id + 1) * ((soundMode == kCLUMode) ? 8 : 12), SEEK_SET);
+ fh->idxTab = (uint32*)malloc(fh->idxLen * 3 * sizeof(uint32));
+ for (uint32 cnt = 0; cnt < fh->idxLen; cnt++) {
+ fh->idxTab[cnt * 3 + 0] = fh->file->readUint32LE();
+ fh->idxTab[cnt * 3 + 1] = fh->file->readUint32LE();
+ if (fh->fileType == kCLUMode)
+ fh->idxTab[cnt * 3 + 2] = fh->idxTab[cnt * 3 + 1] + 1;
+ else
+ fh->idxTab[cnt * 3 + 2] = fh->file->readUint32LE();
+ }
+ }
- uint32 pos = fp->readUint32LE();
- uint32 len = fp->readUint32LE();
- uint32 enc_len;
+ uint32 pos = fh->idxTab[id * 3 + 0];
+ uint32 len = fh->idxTab[id * 3 + 1];
+ uint32 enc_len = fh->idxTab[id * 3 + 2];
if (numSamples)
*numSamples = len;
- if (soundMode != kCLUMode)
- enc_len = fp->readUint32LE();
- else
- enc_len = len + 1;
-
if (!pos || !len) {
- fp->close();
+ fh->file->close();
return NULL;
}
- fp->seek(pos, SEEK_SET);
+ fh->file->seek(pos, SEEK_SET);
- switch (soundMode) {
+ switch (fh->fileType) {
case kCLUMode:
- return makeCLUStream(fp, enc_len);
+ return makeCLUStream(fh->file, enc_len);
#ifdef USE_MAD
case kMP3Mode:
- return makeMP3Stream(fp, enc_len);
+ return makeMP3Stream(fh->file, enc_len);
#endif
#ifdef USE_VORBIS
case kVorbisMode:
- return makeVorbisStream(fp, enc_len);
+ return makeVorbisStream(fh->file, enc_len);
#endif
#ifdef USE_FLAC
case kFlacMode:
- return makeFlacStream(fp, enc_len);
+ return makeFlacStream(fh->file, enc_len);
#endif
default:
return NULL;
@@ -225,9 +236,9 @@ AudioStream *makeCLUStream(File *file, int size) {
// The length of a fade-in/out, in milliseconds.
#define FADE_LENGTH 3000
-MusicInputStream::MusicInputStream(int cd, File *fp, uint32 musicId, bool looping) {
+MusicInputStream::MusicInputStream(int cd, SoundFileHandle *fh, uint32 musicId, bool looping) {
_cd = cd;
- _file = fp;
+ _fh = fh;
_musicId = musicId;
_looping = looping;
@@ -235,7 +246,7 @@ MusicInputStream::MusicInputStream(int cd, File *fp, uint32 musicId, bool loopin
_remove = false;
_fading = 0;
- _decoder = getAudioStream(fp, "music", _cd, _musicId, &_numSamples);
+ _decoder = getAudioStream(_fh, "music", _cd, _musicId, &_numSamples);
if (_decoder) {
_samplesLeft = _numSamples;
_fadeSamples = (getRate() * FADE_LENGTH) / 1000;
@@ -353,7 +364,7 @@ void MusicInputStream::refill() {
if (!_samplesLeft) {
if (_looping) {
delete _decoder;
- _decoder = getAudioStream(_file, "music", _cd, _musicId, &_numSamples);
+ _decoder = getAudioStream(_fh, "music", _cd, _musicId, &_numSamples);
_samplesLeft = _numSamples;
} else
_remove = true;
@@ -448,8 +459,8 @@ int Sound::readBuffer(int16 *buffer, const int numSamples) {
}
for (i = 0; i < MAXMUS; i++) {
- if (!inUse[i] && _musicFile[i].isOpen())
- _musicFile[i].close();
+ if (!inUse[i] && !_musicFile[i].inUse && _musicFile[i].file->isOpen())
+ _musicFile[i].file->close();
}
return numSamples;
@@ -457,7 +468,7 @@ int Sound::readBuffer(int16 *buffer, const int numSamples) {
bool Sound::endOfData() const {
for (int i = 0; i < MAXMUS; i++) {
- if (_musicFile[i].isOpen())
+ if (_musicFile[i].file->isOpen())
return false;
}
@@ -516,8 +527,9 @@ void Sound::stopMusic(bool immediately) {
* @return RD_OK or an error code
*/
int32 Sound::streamCompMusic(uint32 musicId, bool loop) {
- Common::StackLock lock(_mutex);
+ //Common::StackLock lock(_mutex);
+ _mutex.lock();
int cd = _vm->_resman->whichCd();
if (loop)
@@ -572,23 +584,32 @@ int32 Sound::streamCompMusic(uint32 musicId, bool loop) {
primary = 0;
// Don't start streaming if the volume is off.
- if (isMusicMute())
+ if (isMusicMute()) {
+ _mutex.unlock();
return RD_OK;
+ }
if (secondary != -1)
_music[secondary]->fadeDown();
+ SoundFileHandle *fh = (cd == 1) ? &_musicFile[0] : &_musicFile[1];
+ fh->inUse = true;
+ _mutex.unlock();
- File *fp = (cd == 1) ? &_musicFile[0] : &_musicFile[1];
-
- _music[primary] = new MusicInputStream(cd, fp, musicId, loop);
+ MusicInputStream *tmp = new MusicInputStream(cd, fh, musicId, loop);
- if (!_music[primary]->isReady()) {
- delete _music[primary];
- _music[primary] = NULL;
+ if (tmp->isReady()) {
+ _mutex.lock();
+ _music[primary] = tmp;
+ fh->inUse = false;
+ _mutex.unlock();
+ return RD_OK;
+ } else {
+ _mutex.lock();
+ fh->inUse = false;
+ _mutex.unlock();
+ delete tmp;
return RDERR_INVALIDFILENAME;
}
-
- return RD_OK;
}
/**
@@ -685,10 +706,12 @@ int32 Sound::amISpeaking() {
*/
uint32 Sound::preFetchCompSpeech(uint32 speechId, uint16 **buf) {
- File fp;
+ int cd = _vm->_resman->whichCd();
uint32 numSamples;
- AudioStream *input = getAudioStream(&fp, "speech", _vm->_resman->whichCd(), speechId, &numSamples);
+ SoundFileHandle *fh = (cd == 1) ? &_speechFile[0] : &_speechFile[1];
+
+ AudioStream *input = getAudioStream(fh, "speech", cd, speechId, &numSamples);
if (!input)
return 0;
@@ -702,13 +725,13 @@ uint32 Sound::preFetchCompSpeech(uint32 speechId, uint16 **buf) {
*buf = (uint16 *) malloc(bufferSize);
if (!*buf) {
delete input;
- fp.close();
+ fh->file->close();
return 0;
}
uint32 readSamples = input->readBuffer((int16 *) *buf, numSamples);
- fp.close();
+ fh->file->close();
delete input;
return 2 * readSamples;
@@ -729,12 +752,10 @@ int32 Sound::playCompSpeech(uint32 speechId, uint8 vol, int8 pan) {
if (getSpeechStatus() == RDERR_SPEECHPLAYING)
return RDERR_SPEECHPLAYING;
- File *fp = new File;
- AudioStream *input = getAudioStream(fp, "speech", _vm->_resman->whichCd(), speechId, NULL);
+ int cd = _vm->_resman->whichCd();
+ SoundFileHandle *fh = (cd == 1) ? &_speechFile[0] : &_speechFile[1];
- // Make the AudioStream object the sole owner of the file so that it
- // will die along with the AudioStream when the speech has finished.
- fp->decRef();
+ AudioStream *input = getAudioStream(fh, "speech", cd, speechId, NULL);
if (!input)
return RDERR_INVALIDID;
diff --git a/sword2/sound.cpp b/sword2/sound.cpp
index 97155db266..ad6c732b0e 100644
--- a/sword2/sound.cpp
+++ b/sword2/sound.cpp
@@ -50,9 +50,24 @@ Sound::Sound(Sword2Engine *vm) {
for (i = 0; i < FXQ_LENGTH; i++)
_fxQueue[i].resource = 0;
- for (i = 0; i < MAXMUS; i++)
+ for (i = 0; i < MAXMUS; i++) {
_music[i] = NULL;
+ _musicFile[i].file = new File;
+ _musicFile[i].idxTab = NULL;
+ _musicFile[i].idxLen = 0;
+ _musicFile[i].fileSize = 0;
+ _musicFile[i].fileType = 0;
+ _musicFile[i].inUse = false;
+
+ _speechFile[i].file = new File;
+ _speechFile[i].idxTab = NULL;
+ _speechFile[i].idxLen = 0;
+ _speechFile[i].fileSize = 0;
+ _speechFile[i].fileType = 0;
+ _speechFile[i].inUse = false;
+ }
+
_speechPaused = false;
_musicPaused = false;
_fxPaused = false;
@@ -77,8 +92,10 @@ Sound::~Sound() {
free(_mixBuffer);
for (int i = 0; i < MAXMUS; i++) {
- if (_musicFile[i].isOpen())
- _musicFile[i].close();
+ if (_musicFile[i].file->isOpen())
+ _musicFile[i].file->close();
+ if (_speechFile[i].file->isOpen())
+ _speechFile[i].file->close();
}
}
diff --git a/sword2/sound.h b/sword2/sound.h
index 64b441ff51..cb3d69e851 100644
--- a/sword2/sound.h
+++ b/sword2/sound.h
@@ -93,10 +93,20 @@ public:
int getRate() const { return 22050; }
};
+struct SoundFileHandle {
+ File *file;
+ uint32 *idxTab;
+ uint32 idxLen;
+ uint32 fileSize;
+ uint32 fileType;
+ volatile bool inUse;
+};
+
class MusicInputStream : public AudioStream {
private:
int _cd;
- File *_file;
+ //File *_file;
+ SoundFileHandle *_fh;
uint32 _musicId;
AudioStream *_decoder;
int16 _buffer[BUFFER_SIZE];
@@ -119,7 +129,7 @@ private:
}
public:
- MusicInputStream(int cd, File *fp, uint32 musicId, bool looping);
+ MusicInputStream(int cd, SoundFileHandle *fh, uint32 musicId, bool looping);
~MusicInputStream();
int readBuffer(int16 *buffer, const int numSamples);
@@ -176,7 +186,9 @@ private:
PlayingSoundHandle _soundHandleSpeech;
MusicInputStream *_music[MAXMUS];
- File _musicFile[MAXMUS];
+ //File _musicFile[MAXMUS];
+ SoundFileHandle _musicFile[MAXMUS];
+ SoundFileHandle _speechFile[MAXMUS];
int16 *_mixBuffer;
int _mixBufferLen;