From cb40356a7bd34f3ad3c32ea6fea86f52545746f3 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 20 Feb 2007 23:40:46 +0000 Subject: [PATCH] Revamed the Ogg Vorbis & FLAC DigitalTrackInfo subclasses to work similar to the MP3 one (i.e. only open the data file when about to play) svn-id: r25757 --- sound/flac.cpp | 72 ++++++++------- sound/mp3.cpp | 26 +++--- sound/vorbis.cpp | 223 +++++++++++++++++++++-------------------------- 3 files changed, 153 insertions(+), 168 deletions(-) diff --git a/sound/flac.cpp b/sound/flac.cpp index 94398a69462..b68393fffc4 100644 --- a/sound/flac.cpp +++ b/sound/flac.cpp @@ -874,41 +874,57 @@ void FlacInputStream::callWrapError(const ::FLAC__SeekableStreamDecoder *decoder class FlacTrackInfo : public DigitalTrackInfo { private: - File *_file; - FlacInputStream *_firstStream; // avoid having to open the Stream twice the first time + Common::String _filename; + bool _errorFlag; public: - FlacTrackInfo(File *file); - ~FlacTrackInfo(); - bool error() { return _file == NULL; } + FlacTrackInfo(const char *filename); + bool error() { return _errorFlag; } void play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int startFrame, int duration); }; -FlacTrackInfo::FlacTrackInfo(File *file) : _file(NULL), _firstStream(NULL) { - FlacInputStream *tempStream = new FlacInputStream(file); - /* first time the file will be tested, but not used */ - if (tempStream->init()) { - _firstStream = tempStream; - _file = file; - } else - delete tempStream; +FlacTrackInfo::FlacTrackInfo(const char *filename) : + _filename(filename), + _errorFlag(false) { + + // Try to open the file + Common::File file; + if (!file.open(_filename)) { + _errorFlag = true; + return; + } + + // Next, try to create a FlacInputStream from it + FlacInputStream *tempStream = new FlacInputStream(&file); + + // If initialising the stream fails, we set the error flag + if (!tempStream || !tempStream->init()) + _errorFlag = true; + + delete tempStream; } void FlacTrackInfo::play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int startFrame, int duration) { + assert(!_errorFlag); + if (error()) { debug(1, "FlacTrackInfo::play: invalid state, method should not been called"); } - FlacInputStream *flac; - - if (_firstStream != NULL) { - flac = _firstStream; - _firstStream = NULL; - } else { - flac = new FlacInputStream(_file); - flac->init(); + // Open the file + Common::File *file = new Common::File(); + if (!file || !file->open(_filename)) { + warning("FlacTrackInfo::play: failed to open '%s'", _filename.c_str()); + delete file; + return; } + // Create an AudioStream from the file + FlacInputStream *flac = new FlacInputStream(file); + flac->init(); + file->decRef(); + + // Seek to the correct start position and start playback if (flac->isStreamDecoderReady()) { const FLAC__StreamMetadata_StreamInfo &info = flac->getStreamInfo(); if (duration) @@ -921,38 +937,30 @@ void FlacTrackInfo::play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int st return; } // startSample is beyond the existing Samples - debug(1, "FlacTrackInfo: Audiostream %s could not seek to frame %d (ca %d secs)", _file->name(), startFrame, startFrame/75); + debug(1, "FlacTrackInfo: Audiostream %s could not seek to frame %d (ca %d secs)", _filename.c_str(), startFrame, startFrame/75); flac->finish(); } delete flac; } -FlacTrackInfo::~FlacTrackInfo() { - delete _firstStream; - delete _file; -} - DigitalTrackInfo* getFlacTrack(int track) { assert(track >= 1); char trackName[4][32]; - File *file = new File(); sprintf(trackName[0], "track%d.flac", track); sprintf(trackName[1], "track%02d.flac", track); sprintf(trackName[2], "track%d.fla", track); sprintf(trackName[3], "track%02d.fla", track); - for (int i = 0; i < 4; ++i) { - if (file->open(trackName[i])) { - FlacTrackInfo *trackInfo = new FlacTrackInfo(file); + if (Common::File::exists(trackName[i])) { + FlacTrackInfo *trackInfo = new FlacTrackInfo(trackName[i]); if (!trackInfo->error()) return trackInfo; delete trackInfo; } } - delete file; return NULL; } diff --git a/sound/mp3.cpp b/sound/mp3.cpp index 1ac43cdfd5d..7fbcb44b5f9 100644 --- a/sound/mp3.cpp +++ b/sound/mp3.cpp @@ -167,7 +167,7 @@ void MP3InputStream::decodeMP3Data() { if (_stream.error == MAD_ERROR_BUFLEN) { break; // Read more data } else if (MAD_RECOVERABLE(_stream.error)) { - debug(1, "MP3InputStream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); + debug(6, "MP3InputStream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); continue; } else { warning("MP3InputStream: Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); @@ -193,8 +193,10 @@ void MP3InputStream::decodeMP3Data() { if (_stream.error == MAD_ERROR_BUFLEN) { break; // Read more data } else if (MAD_RECOVERABLE(_stream.error)) { - // FIXME: should we do anything here? - debug(1, "MP3InputStream: Recoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream)); + // Note: we will occasionally see MAD_ERROR_BADDATAPTR errors here. + // These are normal and expected (caused by our frame skipping (i.e. "seeking") + // code above). + debug(6, "MP3InputStream: Recoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream)); continue; } else { warning("MP3InputStream: Unrecoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream)); @@ -351,27 +353,27 @@ MP3TrackInfo::MP3TrackInfo(const char *filename) : _filename(filename), _errorFlag(false) { - Common::File file; - // Try to open the file + Common::File file; if (!file.open(_filename)) { _errorFlag = true; return; } - // Next, try to create a MP3InputStream from it - - MP3InputStream *mp3Stream = new MP3InputStream(&file, false); + // Next, try to create an MP3InputStream from it + MP3InputStream *tempStream = new MP3InputStream(&file, false); // If we see EOS here then that means that not (enough) valid input // data was given. - _errorFlag = mp3Stream->endOfData(); + _errorFlag = tempStream->endOfData(); // Clean up again - delete mp3Stream; + delete tempStream; } void MP3TrackInfo::play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int startFrame, int duration) { + assert(!_errorFlag); + mad_timer_t start; mad_timer_t end; @@ -389,12 +391,14 @@ void MP3TrackInfo::play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int sta Common::File *file = new Common::File(); if (!file || !file->open(_filename)) { warning("MP3TrackInfo::play: failed to open '%s'", _filename.c_str()); + delete file; return; } - // Play it + // ... create an AudioStream ... MP3InputStream *input = new MP3InputStream(file, true, start, end); + // ... and play it mixer->playInputStream(Audio::Mixer::kMusicSoundType, handle, input); } diff --git a/sound/vorbis.cpp b/sound/vorbis.cpp index 7f9fd8d41c9..7df6fbee8b1 100644 --- a/sound/vorbis.cpp +++ b/sound/vorbis.cpp @@ -46,8 +46,6 @@ using Common::File; namespace Audio { -static AudioStream *makeVorbisStream(OggVorbis_File *file, int duration); - // These are wrapper functions to allow using a File object to // provide data to the OggVorbis_File object. @@ -129,8 +127,9 @@ static int seek_wrap(void *datasource, ogg_int64_t offset, int whence) { static int close_wrap(void *datasource) { file_info *f = (file_info *) datasource; - f->file->decRef(); + delete f->file; delete f; + return 0; } @@ -145,123 +144,6 @@ static ov_callbacks g_File_wrap = { }; -#pragma mark - -#pragma mark --- Ogg Vorbis Audio CD emulation --- -#pragma mark - - -class VorbisTrackInfo : public DigitalTrackInfo { -private: - File *_file; - OggVorbis_File _ov_file; - bool _error_flag; - -public: - VorbisTrackInfo(File *file); - ~VorbisTrackInfo(); - bool openTrack(); - bool error() { return _error_flag; } - void play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int startFrame, int duration); -}; - - -VorbisTrackInfo::VorbisTrackInfo(File *file) { -//debug(5, "" __FILE__ ":%i", __LINE__); - - _file = file; - if (openTrack()) { - warning("Invalid file format"); - _error_flag = true; - _file = 0; - } else { - _error_flag = false; - _file->incRef(); - ov_clear(&_ov_file); - } -} - -bool VorbisTrackInfo::openTrack() { -//debug(5, "" __FILE__ ":%i", __LINE__); - assert(_file); - - file_info *f = new file_info; - -#if defined(__SYMBIAN32__) - // Symbian can't share filehandles between different threads. - // So create a new file and seek that to the other filehandles position - f->file = new File; - f->file->open(_file->name()); - f->file->seek(_file->pos()); -#else - f->file = _file; -#endif - - f->start = 0; - f->len = _file->size(); - f->curr_pos = 0; - _file->seek(0); - - bool err = (ov_open_callbacks((void *) f, &_ov_file, NULL, 0, g_File_wrap) < 0); - if (err) { -#ifdef __SYMBIAN32__ - delete f->file; -#endif - delete f; - } else { -#ifndef __SYMBIAN32__ - _file->incRef(); -#endif - } - - return err; -} - -VorbisTrackInfo::~VorbisTrackInfo() { -//debug(5, "" __FILE__ ":%i", __LINE__); - if (! _error_flag) { - ov_clear(&_ov_file); - _file->decRef(); - } -} - -void VorbisTrackInfo::play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int startFrame, int duration) { -//debug(5, "" __FILE__ ":%i", __LINE__); - bool err = openTrack(); err=err;//satisfy unused variable - assert(!err); - -#ifdef USE_TREMOR // In Tremor, the ov_time_seek() and ov_time_seek_page() calls take seeking positions in milliseconds as 64 bit integers, rather than in seconds as doubles as in Vorbisfile. -#if defined(__SYMBIAN32__) && defined(__GCC32__) // SumthinWicked says: fixing "relocation truncated to fit: ARM_26 __fixdfdi" during linking on GCC, see portdefs.h - ov_time_seek(&_ov_file, (ogg_int64_t)scumm_fixdfdi(startFrame / 75.0 * 1000)); -#else - ov_time_seek(&_ov_file, (ogg_int64_t)(startFrame / 75.0 * 1000)); -#endif -#else - ov_time_seek(&_ov_file, startFrame / 75.0); -#endif - - AudioStream *input = makeVorbisStream(&_ov_file, duration * ov_info(&_ov_file, -1)->rate / 75); - mixer->playInputStream(Audio::Mixer::kMusicSoundType, handle, input); -} - -DigitalTrackInfo *getVorbisTrack(int track) { - char trackName[2][32]; - File *file = new File(); - - sprintf(trackName[0], "track%d.ogg", track); - sprintf(trackName[1], "track%02d.ogg", track); - - for (int i = 0; i < 2; ++i) { - if (file->open(trackName[i])) { - VorbisTrackInfo *trackInfo = new VorbisTrackInfo(file); - file->decRef(); - if (!trackInfo->error()) - return trackInfo; - delete trackInfo; - } - } - delete file; - return NULL; -} - #pragma mark - #pragma mark --- Ogg Vorbis stream --- #pragma mark - @@ -376,11 +258,6 @@ void VorbisInputStream::refill() { _bufferEnd = (int16 *)read_pos; } -static AudioStream *makeVorbisStream(OggVorbis_File *file, int duration) { -//debug(5, "" __FILE__ ":%i", __LINE__); - return new VorbisInputStream(file, duration, false); -} - AudioStream *makeVorbisStream(File *file, uint32 size) { //debug(5, "" __FILE__ ":%i", __LINE__); OggVorbis_File *ov_file = new OggVorbis_File; @@ -413,6 +290,102 @@ AudioStream *makeVorbisStream(File *file, uint32 size) { } +#pragma mark - +#pragma mark --- Ogg Vorbis Audio CD emulation --- +#pragma mark - + +class VorbisTrackInfo : public DigitalTrackInfo { +private: + Common::String _filename; + bool _errorFlag; + +public: + VorbisTrackInfo(const char *filename); + bool openTrack(OggVorbis_File *ovFile); + bool error() { return _errorFlag; } + void play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int startFrame, int duration); +}; + + +VorbisTrackInfo::VorbisTrackInfo(const char *filename) : + _filename(filename), + _errorFlag(false) { + + OggVorbis_File ov_file; + _errorFlag = openTrack(&ov_file); + + if (!_errorFlag) + ov_clear(&ov_file); +} + +bool VorbisTrackInfo::openTrack(OggVorbis_File *ovFile) { + bool err; + + file_info *f = new file_info; + assert(f); + f->file = new File; + assert(f->file); + + err = !f->file->open(_filename); + + if (!err) { + f->start = 0; + f->len = f->file->size(); + f->curr_pos = 0; + + err = (ov_open_callbacks((void *) f, ovFile, NULL, 0, g_File_wrap) < 0); + } + + if (err) { + delete f->file; + delete f; + } + + return err; +} + +void VorbisTrackInfo::play(Audio::Mixer *mixer, Audio::SoundHandle *handle, int startFrame, int duration) { + OggVorbis_File *ovFile = new OggVorbis_File; + bool err = openTrack(ovFile); + assert(!err); + +#ifdef USE_TREMOR + // In Tremor, the ov_time_seek() and ov_time_seek_page() calls take seeking + // positions in milliseconds as 64 bit integers, rather than in seconds as + // doubles as in Vorbisfile. +#if defined(__SYMBIAN32__) && defined(__GCC32__) + // SumthinWicked says: fixing "relocation truncated to fit: ARM_26 __fixdfdi" during linking on GCC, see portdefs.h + ov_time_seek(ovFile, (ogg_int64_t)scumm_fixdfdi(startFrame / 75.0 * 1000)); +#else + ov_time_seek(ovFile, (ogg_int64_t)(startFrame / 75.0 * 1000)); +#endif +#else + ov_time_seek(ovFile, startFrame / 75.0); +#endif + + AudioStream *input = new VorbisInputStream(ovFile, duration * ov_info(ovFile, -1)->rate / 75, true); + mixer->playInputStream(Audio::Mixer::kMusicSoundType, handle, input); +} + +DigitalTrackInfo *getVorbisTrack(int track) { + char trackName[2][32]; + + sprintf(trackName[0], "track%d.ogg", track); + sprintf(trackName[1], "track%02d.ogg", track); + + for (int i = 0; i < 2; ++i) { + if (Common::File::exists(trackName[i])) { + VorbisTrackInfo *trackInfo = new VorbisTrackInfo(trackName[i]); + if (!trackInfo->error()) + return trackInfo; + delete trackInfo; + } + } + return NULL; +} + + + } // End of namespace Audio #endif // #ifdef USE_VORBIS