Index: scumm/sound.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/sound.cpp,v
retrieving revision 1.43
diff -u -r1.43 sound.cpp
--- scumm/sound.cpp	27 Oct 2002 01:12:09 -0000	1.43
+++ scumm/sound.cpp	27 Oct 2002 08:49:43 -0000
@@ -738,16 +738,24 @@
 	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 @@
 #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 @@
 	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 @@
 }
 
 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() {
Index: scumm/sound.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/sound.h,v
retrieving revision 1.15
diff -u -r1.15 sound.h
--- scumm/sound.h	27 Oct 2002 01:12:09 -0000	1.15
+++ scumm/sound.h	27 Oct 2002 08:49:43 -0000
@@ -68,6 +68,7 @@
 #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 @@
 	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();
Index: sound/mixer.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/mixer.cpp,v
retrieving revision 1.21
diff -u -r1.21 mixer.cpp
--- sound/mixer.cpp	27 Oct 2002 01:12:10 -0000	1.21
+++ sound/mixer.cpp	27 Oct 2002 08:49:43 -0000
@@ -145,10 +145,10 @@
 #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 @@
 #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 @@
 	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 @@
 			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 @@
 	}
 
 	delete [] samples;
+
+	if (_eof_flag && ! _is_cd_track)
+		realDestroy();
 }
 
 void SoundMixer::ChannelVorbis::realDestroy() {
@@ -1054,7 +1063,7 @@
 
 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
Index: sound/mixer.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/sound/mixer.h,v
retrieving revision 1.11
diff -u -r1.11 mixer.h
--- sound/mixer.h	27 Oct 2002 01:12:10 -0000	1.11
+++ sound/mixer.h	27 Oct 2002 08:49:43 -0000
@@ -146,11 +146,11 @@
 	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 @@
 	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 */
