From c7dad332fa6f8cf3ae88d638cd0c990524966e14 Mon Sep 17 00:00:00 2001 From: Robert Göffringmann Date: Mon, 21 Feb 2005 08:35:18 +0000 Subject: 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 --- sword2/driver/d_sound.cpp | 195 +++++++++++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 87 deletions(-) (limited to 'sword2/driver') 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; -- cgit v1.2.3