aboutsummaryrefslogtreecommitdiff
path: root/scumm
diff options
context:
space:
mode:
authorJonathan Gray2002-10-27 01:12:10 +0000
committerJonathan Gray2002-10-27 01:12:10 +0000
commitd93e63908659a9601ee29269606500ded088175e (patch)
tree420f1bb6c9a364cf25317622984381d9ae94aeec /scumm
parentf89b40f0276601fb279dd2db03eed30c650df22a (diff)
downloadscummvm-rg350-d93e63908659a9601ee29269606500ded088175e.tar.gz
scummvm-rg350-d93e63908659a9601ee29269606500ded088175e.tar.bz2
scummvm-rg350-d93e63908659a9601ee29269606500ded088175e.zip
patch #628997 support for ogg vorbis instead of cd tracks by Daniel Schepler. Uncomment the relevant lines in the makefile to use
svn-id: r5320
Diffstat (limited to 'scumm')
-rw-r--r--scumm/sound.cpp298
-rw-r--r--scumm/sound.h58
2 files changed, 268 insertions, 88 deletions
diff --git a/scumm/sound.cpp b/scumm/sound.cpp
index a8449a98c9..1c852fd016 100644
--- a/scumm/sound.cpp
+++ b/scumm/sound.cpp
@@ -738,7 +738,7 @@ int Sound::startSfxSound(File *file, int file_size) {
int rate, comp;
byte *data;
-#ifdef COMPRESSED_SOUND_FILE
+#ifdef USE_MAD
if (file_size > 0) {
data = (byte *)calloc(file_size + MAD_BUFFER_GUARD, 1);
@@ -1116,7 +1116,7 @@ int Sound::playSfxSound(void *sound, uint32 size, uint rate, bool isUnsigned) {
}
int Sound::playSfxSound_MP3(void *sound, uint32 size) {
-#ifdef COMPRESSED_SOUND_FILE
+#ifdef USE_MAD
if (_soundsPaused)
return -1;
return _scumm->_mixer->playMP3(NULL, sound, size, SoundMixer::FLAG_AUTOFREE);
@@ -1219,16 +1219,11 @@ int Sound::getCachedTrack(int track) {
char track_name[1024];
File * file = new File();
int current_index;
- struct mad_stream stream;
- struct mad_frame frame;
- unsigned char buffer[8192];
- unsigned int buflen = 0;
- int count = 0;
// See if we find the track in the cache
for (i = 0; i < CACHE_TRACKS; i++)
if (_cached_tracks[i] == track) {
- if (_mp3_tracks[i])
+ if (_track_info[i])
return i;
else
return -1;
@@ -1237,21 +1232,119 @@ int Sound::getCachedTrack(int track) {
_current_cache %= CACHE_TRACKS;
// Not found, see if it exists
+
+ // First, delete the previous track info object
+ delete _track_info[current_index];
+ _track_info[current_index] = NULL;
+
+ _cached_tracks[current_index] = track;
+
+#ifdef USE_MAD
sprintf(track_name, "track%d.mp3", track);
file->open(track_name, _scumm->getGameDataPath());
- _cached_tracks[current_index] = track;
- /* First, close the previous file */
- if (_mp3_tracks[current_index])
- _mp3_tracks[current_index]->close();
+ if (file->isOpen()) {
+ _track_info[current_index] = new MP3TrackInfo(file);
+ if (_track_info[current_index]->error()) {
+ delete _track_info[current_index];
+ _track_info[current_index] = NULL;
+ return -1;
+ }
+ return current_index;
+ }
+#endif
+
+#ifdef USE_VORBIS
+ sprintf(track_name, "track%d.ogg", track);
+ file->open(track_name, _scumm->getGameDataPath());
+
+ if (file->isOpen()) {
+ _track_info[current_index] = new VorbisTrackInfo(file);
+ if (_track_info[current_index]->error()) {
+ delete _track_info[current_index];
+ _track_info[current_index] = NULL;
+ return -1;
+ }
+ return current_index;
+ }
+#endif
+
+ debug(1, "Track %d not available in compressed format", track);
+ return -1;
+}
+
+int Sound::playMP3CDTrack(int track, int num_loops, int start, int delay) {
+ int index;
+ _scumm->_vars[_scumm->VAR_MI1_TIMER] = 0;
+
+ if (_soundsPaused)
+ return 0;
+
+ if ((num_loops == 0) && (start == 0)) {
+ return 0;
+ }
+
+ index = getCachedTrack(track);
+ if (index < 0)
+ return -1;
+
+ if (_dig_cd_playing)
+ _scumm->_mixer->stop(_dig_cd_index);
+ _dig_cd_index = _track_info[index]->play(_scumm->_mixer, start, delay);
+ _dig_cd_playing = true;
+ _dig_cd_track = track;
+ _dig_cd_num_loops = num_loops;
+ _dig_cd_start = start;
+ _dig_cd_delay = delay;
+ return 0;
+}
+
+int Sound::stopMP3CD() {
+ if (_dig_cd_playing == true) {
+ _scumm->_mixer->stop(_dig_cd_index);
+ _dig_cd_playing = false;
+ _dig_cd_track = 0;
+ _dig_cd_num_loops = 0;
+ _dig_cd_start = 0;
+ _dig_cd_delay = 0;
+ return 0;
+ }
+ return -1;
+}
+
+int Sound::pollMP3CD() {
+ if (_dig_cd_playing == true)
+ return 1;
+ return 0;
+}
+
+int Sound::updateMP3CD() {
+ if (_dig_cd_playing == false)
+ return -1;
- _mp3_tracks[current_index] = NULL;
- if (file->isOpen() == false) {
- // This warning is pretty pointless.
- debug(1, "Track %d not available in mp3 format", track);
+ if (_scumm->_mixer->_channels[_dig_cd_index] == NULL) {
+ warning("Error in MP3 decoding");
return -1;
}
+ if (_scumm->_mixer->_channels[_dig_cd_index]->soundFinished()) {
+ if (_dig_cd_num_loops == -1 || --_dig_cd_num_loops > 0)
+ playMP3CDTrack(_dig_cd_track, _dig_cd_num_loops, _dig_cd_start, _dig_cd_delay);
+ else
+ stopMP3CD();
+ }
+
+ return 0;
+}
+
+#ifdef USE_MAD
+Sound::MP3TrackInfo::MP3TrackInfo(File *file) {
+ struct mad_stream stream;
+ struct mad_frame frame;
+ unsigned char buffer[8192];
+ unsigned int buflen = 0;
+ int count = 0;
+
// Check the format and bitrate
mad_stream_init(&stream);
mad_frame_init(&frame);
@@ -1263,7 +1356,7 @@ int Sound::getCachedTrack(int track) {
bytes = file->read(buffer + buflen, sizeof(buffer) - buflen);
if (bytes <= 0) {
if (bytes == -1) {
- warning("Invalid format for track %d", track);
+ warning("Invalid file format");
goto error;
}
break;
@@ -1295,105 +1388,154 @@ int Sound::getCachedTrack(int track) {
}
if (count)
- memcpy(&_mad_header[current_index], &frame.header, sizeof(mad_header));
+ memcpy(&_mad_header, &frame.header, sizeof(mad_header));
else {
- warning("Invalid format for track %d", track);
+ warning("Invalid file format");
goto error;
}
mad_frame_finish(&frame);
mad_stream_finish(&stream);
// Get file size
- _mp3_size[current_index] = file->size();
- _mp3_tracks[current_index] = file;
-
- return current_index;
+ _size = file->size();
+ _file = file;
+ _error_flag = false;
+ return;
error:
mad_frame_finish(&frame);
mad_stream_finish(&stream);
+ _error_flag = true;
delete file;
-
- return -1;
}
-int Sound::playMP3CDTrack(int track, int num_loops, int start, int delay) {
- int index;
+int Sound::MP3TrackInfo::play(SoundMixer *mixer, int start, int delay) {
unsigned int offset;
mad_timer_t duration;
- _scumm->_vars[_scumm->VAR_MI1_TIMER] = 0;
-
- if (_soundsPaused)
- return 0;
-
- if ((num_loops == 0) && (start == 0)) {
- return 0;
- }
-
- index = getCachedTrack(track);
- if (index < 0)
- return -1;
// Calc offset. As all bitrates are in kilobit per seconds, the division by 200 is always exact
- offset = (start * (_mad_header[index].bitrate / (8 * 25))) / 3;
+ offset = (start * (_mad_header.bitrate / (8 * 25))) / 3;
// Calc delay
if (!delay) {
- mad_timer_set(&duration, (_mp3_size[index] * 8) / _mad_header[index].bitrate,
- (_mp3_size[index] * 8) % _mad_header[index].bitrate, _mad_header[index].bitrate);
+ mad_timer_set(&duration, (_size * 8) / _mad_header.bitrate,
+ (_size * 8) % _mad_header.bitrate, _mad_header.bitrate);
} else {
mad_timer_set(&duration, delay / 75, delay % 75, 75);
}
// Go
- _mp3_tracks[index]->seek(offset, SEEK_SET);
-
- if (_mp3_cd_playing == true)
- _scumm->_mixer->stop(_mp3_index);
- _mp3_index = _scumm->_mixer->playMP3CDTrack(NULL, _mp3_tracks[index], duration);
- _mp3_cd_playing = true;
- _mp3_cd_track = track;
- _mp3_cd_num_loops = num_loops;
- _mp3_cd_start = start;
- _mp3_cd_delay = delay;
- return 0;
+ _file->seek(offset, SEEK_SET);
+
+ return mixer->playMP3CDTrack(NULL, _file, duration);
}
-int Sound::stopMP3CD() {
- if (_mp3_cd_playing == true) {
- _scumm->_mixer->stop(_mp3_index);
- _mp3_cd_playing = false;
- _mp3_cd_track = 0;
- _mp3_cd_num_loops = 0;
- _mp3_cd_start = 0;
- _mp3_cd_delay = 0;
- return 0;
+Sound::MP3TrackInfo::~MP3TrackInfo() {
+ if (! _error_flag)
+ _file->close();
+}
+
+#endif
+
+#ifdef USE_VORBIS
+// These are wrapper functions to allow using a File object to
+// provide data to the OggVorbis_File object.
+
+struct file_info {
+ File *file;
+ int start, curr_pos;
+ size_t len;
+};
+
+static size_t read_wrap(void *ptr, size_t size, size_t nmemb, void *datasource) {
+ file_info *f = (file_info *) datasource;
+ int result;
+
+ nmemb *= size;
+ if (f->curr_pos > (int) f->len)
+ nmemb = 0;
+ else if (nmemb > f->len - f->curr_pos)
+ nmemb = f->len - f->curr_pos;
+ result = f->file->read(ptr, nmemb);
+ if (result == -1) {
+ f->curr_pos = f->file->pos() - f->start;
+ return (size_t) -1;
+ }
+ else {
+ f->curr_pos += result;
+ return result / size;
}
- return -1;
}
-int Sound::pollMP3CD() {
- if (_mp3_cd_playing == true)
- return 1;
+static int seek_wrap(void *datasource, ogg_int64_t offset, int whence) {
+ file_info *f = (file_info *) datasource;
+
+ if (whence == SEEK_SET)
+ offset += f->start;
+ else if (whence == SEEK_END) {
+ offset += f->start + f->len;
+ whence = SEEK_SET;
+ }
+
+ f->file->seek(offset, whence);
+ f->curr_pos = f->file->pos() - f->start;
+ return f->curr_pos;
+}
+
+static int close_wrap(void *datasource) {
+ file_info *f = (file_info *) datasource;
+
+ f->file->close();
+ delete f;
return 0;
}
-int Sound::updateMP3CD() {
- if (_mp3_cd_playing == false)
- return -1;
+static long tell_wrap(void *datasource) {
+ file_info *f = (file_info *) datasource;
- if (_scumm->_mixer->_channels[_mp3_index] == NULL) {
- warning("Error in MP3 decoding");
- return -1;
+ return f->file->pos();
+}
+
+static ov_callbacks File_wrap = {
+ read_wrap, seek_wrap, close_wrap, tell_wrap
+};
+
+Sound::VorbisTrackInfo::VorbisTrackInfo(File *file) {
+ file_info *f = new file_info;
+
+ f->file = file;
+ f->start = 0;
+ f->len = file->size();
+ f->curr_pos = file->pos();
+
+ if (ov_open_callbacks((void *) f, &_ov_file, NULL, 0, File_wrap) < 0) {
+ warning("Invalid file format");
+ _error_flag = true;
+ delete f;
+ delete file;
}
+ else {
+ _error_flag = false;
+ _file = file;
- if (_scumm->_mixer->_channels[_mp3_index]->soundFinished()) {
- if (_mp3_cd_num_loops == -1 || --_mp3_cd_num_loops > 0)
- playMP3CDTrack(_mp3_cd_track, _mp3_cd_num_loops, _mp3_cd_start, _mp3_cd_delay);
- else
- stopMP3CD();
+ // Check the file format
+ if (ov_info(&_ov_file, -1)->rate != 22050)
+ warning("Vorbis code currently only supports files encoded at 22050 Hz");
}
+}
- return 0;
+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);
+}
+
+Sound::VorbisTrackInfo::~VorbisTrackInfo() {
+ if (! _error_flag) {
+ ov_clear(&_ov_file);
+ delete _file;
+ }
}
+
+#endif
+
#endif
diff --git a/scumm/sound.h b/scumm/sound.h
index 2f4ddec5c8..635fda5531 100644
--- a/scumm/sound.h
+++ b/scumm/sound.h
@@ -65,24 +65,62 @@ enum {
uint16 _mouthSyncTimes[52];
uint _curSoundPos;
+#ifdef COMPRESSED_SOUND_FILE
MP3OffsetTable *offset_table; // SO3 MP3 compressed audio
int num_sound_effects; // SO3 MP3 compressed audio
-#ifdef COMPRESSED_SOUND_FILE
#define CACHE_TRACKS 10
/* used for mp3 CD music */
int _cached_tracks[CACHE_TRACKS];
- struct mad_header _mad_header[CACHE_TRACKS];
- long _mp3_size[CACHE_TRACKS];
- File *_mp3_tracks[CACHE_TRACKS];
- int _mp3_index;
- int _mp3_cd_track;
- int _mp3_cd_start;
- int _mp3_cd_delay;
- int _mp3_cd_num_loops;
- bool _mp3_cd_playing;
+ int _dig_cd_index;
+ int _dig_cd_track;
+ int _dig_cd_start;
+ int _dig_cd_delay;
+ int _dig_cd_num_loops;
+ bool _dig_cd_playing;
+
+ class DigitalTrackInfo {
+ public:
+ virtual bool error() = 0;
+ virtual int play(SoundMixer *mixer, int start, int delay) = 0;
+ virtual ~DigitalTrackInfo() { }
+ };
+
+ DigitalTrackInfo *_track_info[CACHE_TRACKS];
+
+#ifdef USE_MAD
+ class MP3TrackInfo : public DigitalTrackInfo {
+ private:
+ struct mad_header _mad_header;
+ long _size;
+ File *_file;
+ bool _error_flag;
+
+ public:
+ MP3TrackInfo(File *file);
+ ~MP3TrackInfo();
+ bool error() { return _error_flag; }
+ int play(SoundMixer *mixer, int start, int delay);
+ };
+#endif
+
+#ifdef USE_VORBIS
+ class VorbisTrackInfo : public DigitalTrackInfo {
+ private:
+ File *_file;
+ OggVorbis_File _ov_file;
+ bool _error_flag;
+
+ public:
+ VorbisTrackInfo(File *file);
+ ~VorbisTrackInfo();
+ bool error() { return _error_flag; }
+ int play(SoundMixer *mixer, int start, int delay);
+ };
+#endif
+
#endif
Scumm * _scumm;