diff options
-rw-r--r-- | Makefile.mingw | 4 | ||||
-rw-r--r-- | scumm/sound.cpp | 120 | ||||
-rw-r--r-- | scumm/sound.h | 2 | ||||
-rw-r--r-- | sound/mixer.cpp | 21 | ||||
-rw-r--r-- | sound/mixer.h | 8 |
5 files changed, 138 insertions, 17 deletions
diff --git a/Makefile.mingw b/Makefile.mingw index 5f7dd97d19..02251ea2ca 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -36,8 +36,8 @@ DEFINES += -DUSE_MAD LIBS += -lmad # Uncomment this to activate the Ogg Vorbis lib for compressed sound files -# DEFINES += -DUSE_VORBIS -# LIBS += -lvorbisfile -lvorbis +DEFINES += -DUSE_VORBIS +LIBS += -lvorbisfile -lvorbis -logg # Uncomment this to activate extended debugging support in Simon DEFINES += -DSIMONDEBUG diff --git a/scumm/sound.cpp b/scumm/sound.cpp index 1c852fd016..49a5530930 100644 --- a/scumm/sound.cpp +++ b/scumm/sound.cpp @@ -738,16 +738,24 @@ int Sound::startSfxSound(File *file, int file_size) { int rate, comp; byte *data; -#ifdef USE_MAD +#ifdef COMPRESSED_SOUND_FILE if (file_size > 0) { - data = (byte *)calloc(file_size + MAD_BUFFER_GUARD, 1); + int alloc_size = file_size; +#ifdef USE_MAD + if (! _vorbis_mode) + alloc_size += MAD_BUFFER_GUARD; +#endif + data = (byte *)calloc(alloc_size, 1); if (file->read(data, file_size) != (uint)file_size) { /* no need to free the memory since error will shut down */ error("startSfxSound: cannot read %d bytes", size); return -1; } - return playSfxSound_MP3(data, file_size); + if (_vorbis_mode) + return playSfxSound_Vorbis(data, file_size); + else + return playSfxSound_MP3(data, file_size); } #endif if (file->read(ident, 8) != 8) @@ -805,10 +813,25 @@ File * Sound::openSfxFile() { #ifdef COMPRESSED_SOUND_FILE offset_table = NULL; +#ifdef USE_MAD sprintf(buf, "%s.so3", _scumm->_exe_name); if (!file->open(buf, _scumm->getGameDataPath())) { file->open("monster.so3", _scumm->getGameDataPath()); } + if (file->isOpen()) + _vorbis_mode = false; + else +#endif +#ifdef USE_VORBIS + { + sprintf(buf, "%s.sog", _scumm->_exe_name); + if (!file->open(buf, _scumm->getGameDataPath())) + file->open("monster.sog", _scumm->getGameDataPath()); + if (file->isOpen()) + _vorbis_mode = true; + } +#endif + if (file->isOpen() == true) { /* Now load the 'offset' index in memory to be able to find the MP3 data @@ -1124,6 +1147,91 @@ int Sound::playSfxSound_MP3(void *sound, uint32 size) { return -1; } +#ifdef USE_VORBIS +// Provide a virtual file to vorbisfile based on preloaded data +struct data_file_info { + char *data; + uint32 size; + int curr_pos; +}; + +static size_t read_data(void *ptr, size_t size, size_t nmemb, void *datasource) { + data_file_info *f = (data_file_info *) datasource; + + nmemb *= size; + if (f->curr_pos < 0) + return (size_t) -1; + if (f->curr_pos > (int) f->size) + nmemb = 0; + else if (f->curr_pos + nmemb > f->size) + nmemb = f->size - f->curr_pos; + + memcpy(ptr, f->data + f->curr_pos, nmemb); + f->curr_pos += nmemb; + return nmemb / size; +} + +static int seek_data(void *datasource, ogg_int64_t offset, int whence) { + data_file_info *f = (data_file_info *) datasource; + + switch (whence) { + case SEEK_SET: + f->curr_pos = offset; + break; + case SEEK_CUR: + f->curr_pos += offset; + break; + case SEEK_END: + f->curr_pos = f->size + offset; + break; + default: + return -1; + } + return f->curr_pos; +} + +static int close_data(void *datasource) { + data_file_info *f = (data_file_info *) datasource; + + free(f->data); + delete f; + return 0; +} + +static long tell_data(void *datasource) { + data_file_info *f = (data_file_info *) datasource; + + return f->curr_pos; +} + +static ov_callbacks data_wrap = { + read_data, seek_data, close_data, tell_data +}; +#endif + +int Sound::playSfxSound_Vorbis(void *sound, uint32 size) { +#ifdef USE_VORBIS + if (_soundsPaused) + return -1; + + OggVorbis_File *ov_file = new OggVorbis_File; + data_file_info *f = new data_file_info; + f->data = (char *) sound; + f->size = size; + f->curr_pos = 0; + + if (ov_open_callbacks((void *) f, ov_file, NULL, 0, data_wrap) < 0) { + warning("Invalid file format"); + delete ov_file; + delete f; + return -1; + } + + return _scumm->_mixer->playVorbis(NULL, ov_file, 0, false); +#endif + return -1; +} + // We use a real timer in an attempt to get better sync with CD tracks. This is // necessary for games like Loom CD. @@ -1525,8 +1633,10 @@ Sound::VorbisTrackInfo::VorbisTrackInfo(File *file) { } int Sound::VorbisTrackInfo::play(SoundMixer *mixer, int start, int delay) { - ov_time_seek(&_ov_file, start / 75.0); - return mixer->playVorbisCDTrack(NULL, &_ov_file, delay / 75.0); + ov_pcm_seek(&_ov_file, start * ov_info(&_ov_file, -1)->rate / 75); + return mixer->playVorbis(NULL, &_ov_file, + delay * ov_info(&_ov_file, -1)->rate / 75, + true); } Sound::VorbisTrackInfo::~VorbisTrackInfo() { diff --git a/scumm/sound.h b/scumm/sound.h index 635fda5531..503d5a5872 100644 --- a/scumm/sound.h +++ b/scumm/sound.h @@ -68,6 +68,7 @@ enum { #ifdef COMPRESSED_SOUND_FILE MP3OffsetTable *offset_table; // SO3 MP3 compressed audio int num_sound_effects; // SO3 MP3 compressed audio + bool _vorbis_mode; // true if using SOG, false if using SO3 #define CACHE_TRACKS 10 @@ -171,6 +172,7 @@ public: byte * readCreativeVocFile(byte * ptr, uint32 & size, uint32 & rate, uint32 & loops); int playSfxSound(void *sound, uint32 size, uint rate, bool isUnsigned); int playSfxSound_MP3(void *sound, uint32 size); + int playSfxSound_Vorbis(void *sound, uint32 size); int readCDTimer(); void startCDTimer(); diff --git a/sound/mixer.cpp b/sound/mixer.cpp index e79a91aa98..73aef6178f 100644 --- a/sound/mixer.cpp +++ b/sound/mixer.cpp @@ -145,10 +145,10 @@ int SoundMixer::playMP3CDTrack(PlayingSoundHandle * handle, File * file, mad_tim #endif #ifdef USE_VORBIS -int SoundMixer::playVorbisCDTrack(PlayingSoundHandle * handle, OggVorbis_File * ov_file, double duration) { +int SoundMixer::playVorbis(PlayingSoundHandle * handle, OggVorbis_File * ov_file, int duration, bool is_cd_track) { for (int i = _beginSlots; i != NUM_CHANNELS; i++) { if (_channels[i] == NULL) { - return insertAt(handle, i, new ChannelVorbis(this, ov_file, duration)); + return insertAt(handle, i, new ChannelVorbis(this, ov_file, duration, is_cd_track)); } } @@ -977,16 +977,17 @@ void SoundMixer::ChannelMP3CDMusic::realDestroy() { #endif #ifdef USE_VORBIS -SoundMixer::ChannelVorbis::ChannelVorbis(SoundMixer * mixer, OggVorbis_File * ov_file, double duration) { +SoundMixer::ChannelVorbis::ChannelVorbis(SoundMixer * mixer, OggVorbis_File * ov_file, int duration, bool is_cd_track) { _mixer = mixer; _ov_file = ov_file; if (duration) - _end_pos = ov_time_tell(ov_file) + duration; + _end_pos = ov_pcm_tell(ov_file) + duration; else _end_pos = 0; _eof_flag = false; + _is_cd_track = is_cd_track; _toBeDestroyed = false; } @@ -1005,7 +1006,8 @@ void SoundMixer::ChannelVorbis::mix(int16 * data, uint len) { uint len_left = len * channels * 2; int16 *samples = new int16[len_left / 2]; char *read_pos = (char *) samples; - int volume = _mixer->_musicVolume; + int volume = _is_cd_track ? _mixer->_musicVolume : + _mixer->_volumeTable[1]; // Read the samples while (len_left > 0) { @@ -1021,6 +1023,10 @@ void SoundMixer::ChannelVorbis::mix(int16 * data, uint len) { memset(read_pos, 0, len_left); break; } + else if (result == OV_HOLE) { + // Possibly recoverable, just warn about it + warning("Corrupted data in Vorbis file"); + } else if (result < 0) { debug(1, "Decode error %d in Vorbis file", result); // Don't delete it yet, that causes problems in @@ -1045,6 +1051,9 @@ void SoundMixer::ChannelVorbis::mix(int16 * data, uint len) { } delete [] samples; + + if (_eof_flag && ! _is_cd_track) + realDestroy(); } void SoundMixer::ChannelVorbis::realDestroy() { @@ -1054,7 +1063,7 @@ void SoundMixer::ChannelVorbis::realDestroy() { bool SoundMixer::ChannelVorbis::soundFinished() { return _eof_flag || (_end_pos > 0 && - ov_time_tell(_ov_file) >= _end_pos); + ov_pcm_tell(_ov_file) >= _end_pos); } #endif diff --git a/sound/mixer.h b/sound/mixer.h index 1fecef27a2..be763c2228 100644 --- a/sound/mixer.h +++ b/sound/mixer.h @@ -146,11 +146,11 @@ private: class ChannelVorbis : public Channel { SoundMixer * _mixer; OggVorbis_File * _ov_file; - double _end_pos; - bool _eof_flag; + int _end_pos; + bool _eof_flag, _is_cd_track; public: - ChannelVorbis(SoundMixer * mixer, OggVorbis_File * ov_file, double duration); + ChannelVorbis(SoundMixer * mixer, OggVorbis_File * ov_file, int duration, bool is_cd_track); void mix(int16 * data, uint len); void realDestroy(); @@ -212,7 +212,7 @@ public: int playMP3CDTrack(PlayingSoundHandle * handle, File * file, mad_timer_t duration); #endif #ifdef USE_VORBIS - int playVorbisCDTrack(PlayingSoundHandle * handle, OggVorbis_File * ov_file, double duration); + int playVorbis(PlayingSoundHandle * handle, OggVorbis_File * ov_file, int duration, bool is_cd_track); #endif /* Premix procedure, useful when using fmopl adlib */ |