aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scumm/sound.cpp387
-rw-r--r--scumm/sound.h23
-rw-r--r--sound/audiocd.cpp152
-rw-r--r--sound/audiocd.h74
-rw-r--r--sound/module.mk5
-rw-r--r--sound/mp3.cpp127
-rw-r--r--sound/mp3.h47
-rw-r--r--sound/vorbis.cpp150
-rw-r--r--sound/vorbis.h49
9 files changed, 614 insertions, 400 deletions
diff --git a/scumm/sound.cpp b/scumm/sound.cpp
index 6e63cb17c1..80857d1bf6 100644
--- a/scumm/sound.cpp
+++ b/scumm/sound.cpp
@@ -32,10 +32,12 @@
#include "common/timer.h"
#include "common/util.h"
+#include "sound/audiocd.h"
#include "sound/mididrv.h"
#include "sound/midiparser.h"
#include "sound/mixer.h"
#include "sound/voc.h"
+#include "sound/vorbis.h"
namespace Scumm {
@@ -52,45 +54,6 @@ struct MP3OffsetTable { /* Compressed Sound (.SO3) */
int compressed_size;
};
-class DigitalTrackInfo {
-public:
- virtual bool error() = 0;
- virtual int play(SoundMixer *mixer, PlayingSoundHandle *handle, int startFrame, int duration) = 0;
- virtual ~DigitalTrackInfo() { }
-};
-
-#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, PlayingSoundHandle *handle, int startFrame, int duration);
-};
-#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, PlayingSoundHandle *handle, int startFrame, int duration);
-};
-#endif
-
-
Sound::Sound(ScummEngine *parent) {
memset(this,0,sizeof(Sound)); // palmos
@@ -101,7 +64,6 @@ Sound::Sound(ScummEngine *parent) {
_musicBundleBufOutput = NULL;
_musicDisk = 0;
_talkChannelHandle = 0;
- _current_cache = 0;
_currentCDSound = 0;
_sfxFile = 0;
@@ -880,7 +842,9 @@ void Sound::startSfxSound(File *file, int file_size, PlayingSoundHandle *handle)
if (file_size > 0) {
if (_vorbis_mode) {
- playSfxSound_Vorbis(file, file_size, handle);
+#ifdef USE_VORBIS
+ playSfxSound_Vorbis(_scumm->_mixer, file, file_size, handle);
+#endif
} else {
#ifdef USE_MAD
_scumm->_mixer->playMP3(handle, file, file_size);
@@ -1360,89 +1324,6 @@ void Sound::playSfxSound(void *sound, uint32 size, uint rate, bool isUnsigned, P
_scumm->_mixer->playRaw(handle, sound, size, rate, flags);
}
-#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;
- }
-}
-
-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;
-}
-
-static long tell_wrap(void *datasource) {
- file_info *f = (file_info *) datasource;
-
- return f->curr_pos;
-}
-
-static ov_callbacks g_File_wrap = {
- read_wrap, seek_wrap, close_wrap, tell_wrap
-};
-#endif
-
-void Sound::playSfxSound_Vorbis(File *file, uint32 size, PlayingSoundHandle *handle) {
-#ifdef USE_VORBIS
-
- OggVorbis_File *ov_file = new OggVorbis_File;
- file_info *f = new file_info;
-
- f->file = file;
- f->start = file->pos();
- f->len = size;
- f->curr_pos = 0;
-
- if (ov_open_callbacks((void *) f, ov_file, NULL, 0, g_File_wrap) < 0) {
- warning("Invalid file format");
- delete ov_file;
- delete f;
- } else
- _scumm->_mixer->playVorbis(handle, ov_file, 0, false);
-#endif
-}
-
// We use a real timer in an attempt to get better sync with CD tracks. This is
// necessary for games like Loom CD.
@@ -1481,23 +1362,9 @@ void Sound::playCDTrack(int track, int numLoops, int startFrame, int duration) {
// Reset the music timer variable at the start of a new track
_scumm->VAR(_scumm->VAR_MUSIC_TIMER) = 0;
- if (!_soundsPaused && (numLoops != 0 || startFrame != 0)) {
- // Try to load the track from a .mp3/.ogg file, and if found, use
- // that. If not found, attempt to do regular Audio CD playback of
- // the requested track.
- int index = getCachedTrack(track);
- if (index >= 0) {
- _scumm->_mixer->stopHandle(_dig_cd.handle);
- _dig_cd.playing = true;
- _dig_cd.track = track;
- _dig_cd.numLoops = numLoops;
- _dig_cd.start = startFrame;
- _dig_cd.duration = duration;
- _track_info[index]->play(_scumm->_mixer, &_dig_cd.handle, _dig_cd.start, _dig_cd.duration);
- } else {
- _scumm->_system->play_cdrom(track, numLoops, startFrame, duration);
- }
- }
+ // Play it
+ if (!_soundsPaused)
+ AudioCD.playCDTrack(track, numLoops, startFrame, duration);
// Start the timer after starting the track. Starting an MP3 track is
// almost instantaneous, but a CD player may take some time. Hopefully
@@ -1506,247 +1373,15 @@ void Sound::playCDTrack(int track, int numLoops, int startFrame, int duration) {
}
void Sound::stopCD() {
-
- if (_dig_cd.playing) {
- _scumm->_mixer->stopHandle(_dig_cd.handle);
- _dig_cd.playing = false;
- } else {
- _scumm->_system->stop_cdrom();
- }
+ AudioCD.stopCD();
}
int Sound::pollCD() const {
- return _dig_cd.playing || _scumm->_system->poll_cdrom();
+ return AudioCD.pollCD();
}
void Sound::updateCD() {
- if (_dig_cd.playing) {
- // If the sound handle is 0, then playback stopped.
- if (!_dig_cd.handle) {
- // If playback just stopped, check if the current track is supposed
- // to be repeated, and if that's the case, play it again. Else, stop
- // the CD explicitly.
- if (_dig_cd.numLoops == -1 || --_dig_cd.numLoops > 0) {
- _scumm->VAR(_scumm->VAR_MUSIC_TIMER) = 0;
- if (!_soundsPaused) {
- int index = getCachedTrack(_dig_cd.track);
- assert(index >= 0);
- _track_info[index]->play(_scumm->_mixer, &_dig_cd.handle, _dig_cd.start, _dig_cd.duration);
- }
- } else {
- _scumm->_mixer->stopHandle(_dig_cd.handle);
- _dig_cd.playing = false;
- }
- }
- } else {
- _scumm->_system->update_cdrom();
- }
-}
-
-int Sound::getCachedTrack(int track) {
- int i;
-#if defined(USE_MAD) || defined(USE_VORBIS)
- char track_name[1024];
- File *file = new File();
-#endif
- int current_index;
-
- // See if we find the track in the cache
- for (i = 0; i < CACHE_TRACKS; i++)
- if (_cached_tracks[i] == track) {
- if (_track_info[i])
- return i;
- else
- return -1;
- }
- current_index = _current_cache++;
- _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());
-
- 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(2, "Track %d not available in compressed format", track);
- return -1;
-}
-
-#ifdef USE_MAD
-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);
-
- while (1) {
- if (buflen < sizeof(buffer)) {
- int bytes;
-
- bytes = file->read(buffer + buflen, sizeof(buffer) - buflen);
- if (bytes <= 0) {
- if (bytes == -1) {
- warning("Invalid file format");
- goto error;
- }
- break;
- }
-
- buflen += bytes;
- }
-
- mad_stream_buffer(&stream, buffer, buflen);
-
- while (1) {
- if (mad_frame_decode(&frame, &stream) == -1) {
- if (!MAD_RECOVERABLE(stream.error))
- break;
-
- if (stream.error != MAD_ERROR_BADCRC)
- continue;
- }
-
- if (count++)
- break;
- }
-
- if (count || stream.error != MAD_ERROR_BUFLEN)
- break;
-
- memmove(buffer, stream.next_frame,
- buflen = &buffer[buflen] - stream.next_frame);
- }
-
- if (count)
- memcpy(&_mad_header, &frame.header, sizeof(mad_header));
- else {
- warning("Invalid file format");
- goto error;
- }
-
- mad_frame_finish(&frame);
- mad_stream_finish(&stream);
- // Get file size
- _size = file->size();
- _file = file;
- _error_flag = false;
- return;
-
-error:
- mad_frame_finish(&frame);
- mad_stream_finish(&stream);
- _error_flag = true;
- delete file;
+ AudioCD.updateCD();
}
-int MP3TrackInfo::play(SoundMixer *mixer, PlayingSoundHandle *handle, int startFrame, int duration) {
- unsigned int offset;
- mad_timer_t durationTime;
-
- // Calc offset. As all bitrates are in kilobit per seconds, the division by 200 is always exact
- offset = (startFrame * (_mad_header.bitrate / (8 * 25))) / 3;
- _file->seek(offset, SEEK_SET);
-
- // Calc delay
- if (!duration) {
- // FIXME: Using _size here is a problem if offset (or equivalently
- // startFrame) is non-zero.
- mad_timer_set(&durationTime, (_size * 8) / _mad_header.bitrate,
- (_size * 8) % _mad_header.bitrate, _mad_header.bitrate);
- } else {
- mad_timer_set(&durationTime, duration / 75, duration % 75, 75);
- }
-
- // Play it
- return mixer->playMP3CDTrack(handle, _file, durationTime);
-}
-
-MP3TrackInfo::~MP3TrackInfo() {
- if (! _error_flag)
- _file->close();
-}
-
-#endif
-
-#ifdef USE_VORBIS
-
-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, g_File_wrap) < 0) {
- warning("Invalid file format");
- _error_flag = true;
- delete f;
- delete file;
- } else {
- _error_flag = false;
- _file = file;
- }
-}
-
-#ifdef CHUNKSIZE
-#define VORBIS_TREMOR
-#endif
-
-int VorbisTrackInfo::play(SoundMixer *mixer, PlayingSoundHandle *handle, int startFrame, int duration) {
-#ifdef VORBIS_TREMOR
- ov_time_seek(&_ov_file, (ogg_int64_t)(startFrame / 75.0 * 1000));
-#else
- ov_time_seek(&_ov_file, startFrame / 75.0);
-#endif
- return mixer->playVorbis(handle, &_ov_file,
- duration * ov_info(&_ov_file, -1)->rate / 75, true);
-}
-
-VorbisTrackInfo::~VorbisTrackInfo() {
- if (! _error_flag) {
- ov_clear(&_ov_file);
- delete _file;
- }
-}
-
-#endif
-
} // End of namespace Scumm
diff --git a/scumm/sound.h b/scumm/sound.h
index 28e9d135a6..e1b6c7c64d 100644
--- a/scumm/sound.h
+++ b/scumm/sound.h
@@ -29,7 +29,6 @@ class File;
namespace Scumm {
class Bundle;
-class DigitalTrackInfo;
class ScummEngine;
struct MP3OffsetTable;
@@ -74,27 +73,8 @@ protected:
int num_sound_effects; // SO3 MP3 compressed audio
bool _vorbis_mode; // true if using SOG, false if using SO3
- enum {
- CACHE_TRACKS = 10
- };
-
- /* used for mp3 CD music */
-
int _currentCDSound;
- int _cached_tracks[CACHE_TRACKS];
- struct {
- PlayingSoundHandle handle;
- int track;
- int start;
- int duration;
- int numLoops;
- bool playing;
- } _dig_cd;
-
- DigitalTrackInfo *_track_info[CACHE_TRACKS];
- int _current_cache;
-
ScummEngine *_scumm;
public:
@@ -147,9 +127,6 @@ protected:
void startSfxSound(File *file, int file_size, PlayingSoundHandle *handle);
bool isSfxFinished() const;
void playSfxSound(void *sound, uint32 size, uint rate, bool isUnsigned, PlayingSoundHandle *handle);
- void playSfxSound_Vorbis(File *file, uint32 size, PlayingSoundHandle *handle);
-
- int getCachedTrack(int track);
};
} // End of namespace Scumm
diff --git a/sound/audiocd.cpp b/sound/audiocd.cpp
new file mode 100644
index 0000000000..6da8cf28aa
--- /dev/null
+++ b/sound/audiocd.cpp
@@ -0,0 +1,152 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+
+#include "sound/audiocd.h"
+#include "sound/mp3.h"
+#include "sound/vorbis.h"
+#include "base/engine.h"
+#include "common/file.h"
+#include "common/util.h"
+
+
+AudioCDManager::AudioCDManager() {
+ _current_cache = 0;
+}
+
+void AudioCDManager::playCDTrack(int track, int numLoops, int startFrame, int duration) {
+ if (numLoops != 0 || startFrame != 0) {
+ // Try to load the track from a .mp3/.ogg file, and if found, use
+ // that. If not found, attempt to do regular Audio CD playback of
+ // the requested track.
+ int index = getCachedTrack(track);
+ if (index >= 0) {
+ g_engine->_mixer->stopHandle(_cd.handle);
+ _cd.playing = true;
+ _cd.track = track;
+ _cd.numLoops = numLoops;
+ _cd.start = startFrame;
+ _cd.duration = duration;
+ _track_info[index]->play(g_engine->_mixer, &_cd.handle, _cd.start, _cd.duration);
+ } else {
+ g_system->play_cdrom(track, numLoops, startFrame, duration);
+ }
+ }
+}
+
+void AudioCDManager::stopCD() {
+ if (_cd.playing) {
+ g_engine->_mixer->stopHandle(_cd.handle);
+ _cd.playing = false;
+ } else {
+ g_system->stop_cdrom();
+ }
+}
+
+int AudioCDManager::pollCD() const {
+ return _cd.playing || g_system->poll_cdrom();
+}
+
+void AudioCDManager::updateCD() {
+ if (_cd.playing) {
+ // If the sound handle is 0, then playback stopped.
+ if (!_cd.handle) {
+ // If playback just stopped, check if the current track is supposed
+ // to be repeated, and if that's the case, play it again. Else, stop
+ // the CD explicitly.
+ if (_cd.numLoops == -1 || --_cd.numLoops > 0) {
+//FIXME _scumm->VAR(_scumm->VAR_MUSIC_TIMER) = 0;
+//FIXME if (!_soundsPaused) {
+ int index = getCachedTrack(_cd.track);
+ assert(index >= 0);
+ _track_info[index]->play(g_engine->_mixer, &_cd.handle, _cd.start, _cd.duration);
+//FIXME }
+ } else {
+ g_engine->_mixer->stopHandle(_cd.handle);
+ _cd.playing = false;
+ }
+ }
+ } else {
+ g_system->update_cdrom();
+ }
+}
+
+int AudioCDManager::getCachedTrack(int track) {
+ int i;
+#if defined(USE_MAD) || defined(USE_VORBIS)
+ char track_name[1024];
+ File *file = new File();
+#endif
+ int current_index;
+
+ // See if we find the track in the cache
+ for (i = 0; i < CACHE_TRACKS; i++)
+ if (_cached_tracks[i] == track) {
+ if (_track_info[i])
+ return i;
+ else
+ return -1;
+ }
+ current_index = _current_cache++;
+ _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, g_engine->getGameDataPath());
+
+ 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, g_engine->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(2, "Track %d not available in compressed format", track);
+ return -1;
+}
diff --git a/sound/audiocd.h b/sound/audiocd.h
new file mode 100644
index 0000000000..c02e50f4f6
--- /dev/null
+++ b/sound/audiocd.h
@@ -0,0 +1,74 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#ifndef SOUND_AUDIOCD_H
+#define SOUND_AUDIOCD_H
+
+#include "stdafx.h"
+#include "common/scummsys.h"
+#include "common/singleton.h"
+#include "sound/mixer.h"
+
+class DigitalTrackInfo {
+public:
+ virtual bool error() = 0;
+ virtual int play(SoundMixer *mixer, PlayingSoundHandle *handle, int startFrame, int duration) = 0;
+ virtual ~DigitalTrackInfo() { }
+};
+
+
+class AudioCDManager : public Common::Singleton<AudioCDManager> {
+public:
+ void playCDTrack(int track, int numLoops, int startFrame, int duration);
+ void stopCD();
+ int pollCD() const;
+ void updateCD();
+
+private:
+ friend class Common::Singleton<AudioCDManager>;
+ AudioCDManager();
+
+ int getCachedTrack(int track);
+
+private:
+ /* used for emulated CD music */
+ enum {
+ CACHE_TRACKS = 10
+ };
+ int _cached_tracks[CACHE_TRACKS];
+ DigitalTrackInfo *_track_info[CACHE_TRACKS];
+ int _current_cache;
+
+ struct {
+ PlayingSoundHandle handle;
+ int track;
+ int start;
+ int duration;
+ int numLoops;
+ bool playing;
+ } _cd;
+
+};
+
+/** Shortcut for accessing the audio CD manager. */
+#define AudioCD AudioCDManager::instance()
+
+#endif
diff --git a/sound/module.mk b/sound/module.mk
index e0974162a5..859a8b9975 100644
--- a/sound/module.mk
+++ b/sound/module.mk
@@ -1,6 +1,7 @@
MODULE := sound
MODULE_OBJS := \
+ sound/audiocd.o \
sound/audiostream.o \
sound/fmopl.o \
sound/mididrv.o \
@@ -8,9 +9,11 @@ MODULE_OBJS := \
sound/midiparser_smf.o \
sound/midiparser_xmidi.o \
sound/mixer.o \
+ sound/mp3.o \
sound/mpu401.o \
sound/rate.o \
- sound/voc.o
+ sound/voc.o \
+ sound/vorbis.o
# sound/resample.o \
MODULE_DIRS += \
diff --git a/sound/mp3.cpp b/sound/mp3.cpp
new file mode 100644
index 0000000000..db73f7f394
--- /dev/null
+++ b/sound/mp3.cpp
@@ -0,0 +1,127 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+
+#include "sound/mp3.h"
+#include "common/file.h"
+#include "common/util.h"
+
+#ifdef USE_MAD
+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);
+
+ while (1) {
+ if (buflen < sizeof(buffer)) {
+ int bytes;
+
+ bytes = file->read(buffer + buflen, sizeof(buffer) - buflen);
+ if (bytes <= 0) {
+ if (bytes == -1) {
+ warning("Invalid file format");
+ goto error;
+ }
+ break;
+ }
+
+ buflen += bytes;
+ }
+
+ mad_stream_buffer(&stream, buffer, buflen);
+
+ while (1) {
+ if (mad_frame_decode(&frame, &stream) == -1) {
+ if (!MAD_RECOVERABLE(stream.error))
+ break;
+
+ if (stream.error != MAD_ERROR_BADCRC)
+ continue;
+ }
+
+ if (count++)
+ break;
+ }
+
+ if (count || stream.error != MAD_ERROR_BUFLEN)
+ break;
+
+ memmove(buffer, stream.next_frame,
+ buflen = &buffer[buflen] - stream.next_frame);
+ }
+
+ if (count)
+ memcpy(&_mad_header, &frame.header, sizeof(mad_header));
+ else {
+ warning("Invalid file format");
+ goto error;
+ }
+
+ mad_frame_finish(&frame);
+ mad_stream_finish(&stream);
+ // Get file size
+ _size = file->size();
+ _file = file;
+ _error_flag = false;
+ return;
+
+error:
+ mad_frame_finish(&frame);
+ mad_stream_finish(&stream);
+ _error_flag = true;
+ delete file;
+}
+
+int MP3TrackInfo::play(SoundMixer *mixer, PlayingSoundHandle *handle, int startFrame, int duration) {
+ unsigned int offset;
+ mad_timer_t durationTime;
+
+ // Calc offset. As all bitrates are in kilobit per seconds, the division by 200 is always exact
+ offset = (startFrame * (_mad_header.bitrate / (8 * 25))) / 3;
+ _file->seek(offset, SEEK_SET);
+
+ // Calc delay
+ if (!duration) {
+ // FIXME: Using _size here is a problem if offset (or equivalently
+ // startFrame) is non-zero.
+ mad_timer_set(&durationTime, (_size * 8) / _mad_header.bitrate,
+ (_size * 8) % _mad_header.bitrate, _mad_header.bitrate);
+ } else {
+ mad_timer_set(&durationTime, duration / 75, duration % 75, 75);
+ }
+
+ // Play it
+ return mixer->playMP3CDTrack(handle, _file, durationTime);
+}
+
+MP3TrackInfo::~MP3TrackInfo() {
+ if (! _error_flag)
+ _file->close();
+}
+
+#endif
diff --git a/sound/mp3.h b/sound/mp3.h
new file mode 100644
index 0000000000..fd5be63387
--- /dev/null
+++ b/sound/mp3.h
@@ -0,0 +1,47 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#ifndef SOUND_MP3_H
+#define SOUND_MP3_H
+
+#include "sound/audiocd.h"
+
+class File;
+
+#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, PlayingSoundHandle *handle, int startFrame, int duration);
+};
+#endif
+
+
+
+#endif
diff --git a/sound/vorbis.cpp b/sound/vorbis.cpp
new file mode 100644
index 0000000000..cd1a84ad08
--- /dev/null
+++ b/sound/vorbis.cpp
@@ -0,0 +1,150 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+
+#include "sound/vorbis.h"
+#include "common/file.h"
+#include "common/util.h"
+
+#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;
+ }
+}
+
+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;
+}
+
+static long tell_wrap(void *datasource) {
+ file_info *f = (file_info *) datasource;
+
+ return f->curr_pos;
+}
+
+static ov_callbacks g_File_wrap = {
+ read_wrap, seek_wrap, close_wrap, tell_wrap
+};
+#endif
+
+#ifdef USE_VORBIS
+
+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, g_File_wrap) < 0) {
+ warning("Invalid file format");
+ _error_flag = true;
+ delete f;
+ delete file;
+ } else {
+ _error_flag = false;
+ _file = file;
+ }
+}
+
+#ifdef CHUNKSIZE
+#define VORBIS_TREMOR
+#endif
+
+int VorbisTrackInfo::play(SoundMixer *mixer, PlayingSoundHandle *handle, int startFrame, int duration) {
+#ifdef VORBIS_TREMOR
+ ov_time_seek(&_ov_file, (ogg_int64_t)(startFrame / 75.0 * 1000));
+#else
+ ov_time_seek(&_ov_file, startFrame / 75.0);
+#endif
+ return mixer->playVorbis(handle, &_ov_file,
+ duration * ov_info(&_ov_file, -1)->rate / 75, true);
+}
+
+VorbisTrackInfo::~VorbisTrackInfo() {
+ if (! _error_flag) {
+ ov_clear(&_ov_file);
+ delete _file;
+ }
+}
+
+void playSfxSound_Vorbis(SoundMixer *mixer, File *file, uint32 size, PlayingSoundHandle *handle) {
+ OggVorbis_File *ov_file = new OggVorbis_File;
+ file_info *f = new file_info;
+
+ f->file = file;
+ f->start = file->pos();
+ f->len = size;
+ f->curr_pos = 0;
+
+ if (ov_open_callbacks((void *) f, ov_file, NULL, 0, g_File_wrap) < 0) {
+ warning("Invalid file format");
+ delete ov_file;
+ delete f;
+ } else
+ mixer->playVorbis(handle, ov_file, 0, false);
+}
+
+#endif
diff --git a/sound/vorbis.h b/sound/vorbis.h
new file mode 100644
index 0000000000..fcffc1c50d
--- /dev/null
+++ b/sound/vorbis.h
@@ -0,0 +1,49 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#ifndef SOUND_VORBIS_H
+#define SOUND_VORBIS_H
+
+#include "sound/audiocd.h"
+
+class File;
+
+#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, PlayingSoundHandle *handle, int startFrame, int duration);
+};
+
+
+void playSfxSound_Vorbis(SoundMixer *mixer, File *file, uint32 size, PlayingSoundHandle *handle);
+
+#endif
+
+#endif