diff options
author | Max Horn | 2003-11-29 12:11:01 +0000 |
---|---|---|
committer | Max Horn | 2003-11-29 12:11:01 +0000 |
commit | f00cd05b331cb5db1dfee140608d6189385950a4 (patch) | |
tree | db1e0105eb9ef2cd266620357c551c5a058f4d37 | |
parent | 493d64d91b9944cd91da6539cb41ee561ddafd92 (diff) | |
download | scummvm-rg350-f00cd05b331cb5db1dfee140608d6189385950a4.tar.gz scummvm-rg350-f00cd05b331cb5db1dfee140608d6189385950a4.tar.bz2 scummvm-rg350-f00cd05b331cb5db1dfee140608d6189385950a4.zip |
moved Audio CD (emulation) code from scumm/sound.cpp to sound/, so that it may be reused by other engines in the future
svn-id: r11421
-rw-r--r-- | scumm/sound.cpp | 387 | ||||
-rw-r--r-- | scumm/sound.h | 23 | ||||
-rw-r--r-- | sound/audiocd.cpp | 152 | ||||
-rw-r--r-- | sound/audiocd.h | 74 | ||||
-rw-r--r-- | sound/module.mk | 5 | ||||
-rw-r--r-- | sound/mp3.cpp | 127 | ||||
-rw-r--r-- | sound/mp3.h | 47 | ||||
-rw-r--r-- | sound/vorbis.cpp | 150 | ||||
-rw-r--r-- | sound/vorbis.h | 49 |
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 |