aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.mingw4
-rw-r--r--scumm/sound.cpp120
-rw-r--r--scumm/sound.h2
-rw-r--r--sound/mixer.cpp21
-rw-r--r--sound/mixer.h8
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 */