ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

vorbis.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 // Disable symbol overrides for FILE and fseek as those are used in the
00024 // Vorbis headers.
00025 #define FORBIDDEN_SYMBOL_EXCEPTION_FILE
00026 #define FORBIDDEN_SYMBOL_EXCEPTION_fseek
00027 
00028 #include "audio/decoders/vorbis.h"
00029 
00030 #ifdef USE_VORBIS
00031 
00032 #include "common/ptr.h"
00033 #include "common/stream.h"
00034 #include "common/textconsole.h"
00035 #include "common/util.h"
00036 
00037 #include "audio/audiostream.h"
00038 
00039 #ifdef USE_TREMOR
00040 #ifdef USE_TREMOLO
00041 #include <tremolo/ivorbisfile.h>
00042 #else
00043 #include <tremor/ivorbisfile.h>
00044 #endif
00045 #else
00046 #define OV_EXCLUDE_STATIC_CALLBACKS
00047 #include <vorbis/vorbisfile.h>
00048 #endif
00049 
00050 
00051 namespace Audio {
00052 
00053 // These are wrapper functions to allow using a SeekableReadStream object to
00054 // provide data to the OggVorbis_File object.
00055 
00056 static size_t read_stream_wrap(void *ptr, size_t size, size_t nmemb, void *datasource) {
00057     Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource;
00058 
00059     uint32 result = stream->read(ptr, size * nmemb);
00060 
00061     return result / size;
00062 }
00063 
00064 static int seek_stream_wrap(void *datasource, ogg_int64_t offset, int whence) {
00065     Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource;
00066     stream->seek((int32)offset, whence);
00067     return stream->pos();
00068 }
00069 
00070 static int close_stream_wrap(void *datasource) {
00071     // Do nothing -- we leave it up to the VorbisStream to free memory as appropriate.
00072     return 0;
00073 }
00074 
00075 static long tell_stream_wrap(void *datasource) {
00076     Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource;
00077     return stream->pos();
00078 }
00079 
00080 static ov_callbacks g_stream_wrap = {
00081     read_stream_wrap, seek_stream_wrap, close_stream_wrap, tell_stream_wrap
00082 };
00083 
00084 
00085 
00086 #pragma mark -
00087 #pragma mark --- Ogg Vorbis stream ---
00088 #pragma mark -
00089 
00090 
00091 class VorbisStream : public SeekableAudioStream {
00092 protected:
00093     Common::DisposablePtr<Common::SeekableReadStream> _inStream;
00094 
00095     bool _isStereo;
00096     int _rate;
00097 
00098     Timestamp _length;
00099 
00100     OggVorbis_File _ovFile;
00101 
00102     int16 _buffer[4096];
00103     const int16 *_bufferEnd;
00104     const int16 *_pos;
00105 
00106 public:
00107     // startTime / duration are in milliseconds
00108     VorbisStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose);
00109     ~VorbisStream();
00110 
00111     int readBuffer(int16 *buffer, const int numSamples);
00112 
00113     bool endOfData() const      { return _pos >= _bufferEnd; }
00114     bool isStereo() const       { return _isStereo; }
00115     int getRate() const         { return _rate; }
00116 
00117     bool seek(const Timestamp &where);
00118     Timestamp getLength() const { return _length; }
00119 protected:
00120     bool refill();
00121 };
00122 
00123 VorbisStream::VorbisStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose) :
00124     _inStream(inStream, dispose),
00125     _length(0, 1000),
00126     _bufferEnd(ARRAYEND(_buffer)) {
00127 
00128     int res = ov_open_callbacks(inStream, &_ovFile, NULL, 0, g_stream_wrap);
00129     if (res < 0) {
00130         warning("Could not create Vorbis stream (%d)", res);
00131         _pos = _bufferEnd;
00132         return;
00133     }
00134 
00135     // Read in initial data
00136     if (!refill())
00137         return;
00138 
00139     // Setup some header information
00140     _isStereo = ov_info(&_ovFile, -1)->channels >= 2;
00141     _rate = ov_info(&_ovFile, -1)->rate;
00142 
00143 #ifdef USE_TREMOR
00144     _length = Timestamp(ov_time_total(&_ovFile, -1), getRate());
00145 #else
00146     _length = Timestamp(uint32(ov_time_total(&_ovFile, -1) * 1000.0), getRate());
00147 #endif
00148 }
00149 
00150 VorbisStream::~VorbisStream() {
00151     ov_clear(&_ovFile);
00152 }
00153 
00154 int VorbisStream::readBuffer(int16 *buffer, const int numSamples) {
00155     int samples = 0;
00156     while (samples < numSamples && _pos < _bufferEnd) {
00157         const int len = MIN(numSamples - samples, (int)(_bufferEnd - _pos));
00158         memcpy(buffer, _pos, len * 2);
00159         buffer += len;
00160         _pos += len;
00161         samples += len;
00162         if (_pos >= _bufferEnd) {
00163             if (!refill())
00164                 break;
00165         }
00166     }
00167     return samples;
00168 }
00169 
00170 bool VorbisStream::seek(const Timestamp &where) {
00171     // Vorbisfile uses the sample pair number, thus we always use "false" for the isStereo parameter
00172     // of the convertTimeToStreamPos helper.
00173     int res = ov_pcm_seek(&_ovFile, convertTimeToStreamPos(where, getRate(), false).totalNumberOfFrames());
00174     if (res) {
00175         warning("Error seeking in Vorbis stream (%d)", res);
00176         _pos = _bufferEnd;
00177         return false;
00178     }
00179 
00180     return refill();
00181 }
00182 
00183 bool VorbisStream::refill() {
00184     // Read the samples
00185     uint len_left = sizeof(_buffer);
00186     char *read_pos = (char *)_buffer;
00187 
00188     while (len_left > 0) {
00189         long result;
00190 
00191 #ifdef USE_TREMOR
00192         // Tremor ov_read() always returns data as signed 16 bit interleaved PCM
00193         // in host byte order. As such, it does not take arguments to request
00194         // specific signedness, byte order or bit depth as in Vorbisfile.
00195         result = ov_read(&_ovFile, read_pos, len_left,
00196                         NULL);
00197 #else
00198 #ifdef SCUMM_BIG_ENDIAN
00199         result = ov_read(&_ovFile, read_pos, len_left,
00200                         1,
00201                         2,  // 16 bit
00202                         1,  // signed
00203                         NULL);
00204 #else
00205         result = ov_read(&_ovFile, read_pos, len_left,
00206                         0,
00207                         2,  // 16 bit
00208                         1,  // signed
00209                         NULL);
00210 #endif
00211 #endif
00212         if (result == OV_HOLE) {
00213             // Possibly recoverable, just warn about it
00214             warning("Corrupted data in Vorbis file");
00215         } else if (result == 0) {
00216             //warning("End of file while reading from Vorbis file");
00217             //_pos = _bufferEnd;
00218             //return false;
00219             break;
00220         } else if (result < 0) {
00221             warning("Error reading from Vorbis stream (%d)", int(result));
00222             _pos = _bufferEnd;
00223             // Don't delete it yet, that causes problems in
00224             // the CD player emulation code.
00225             return false;
00226         } else {
00227             len_left -= result;
00228             read_pos += result;
00229         }
00230     }
00231 
00232     _pos = _buffer;
00233     _bufferEnd = (int16 *)read_pos;
00234 
00235     return true;
00236 }
00237 
00238 
00239 #pragma mark -
00240 #pragma mark --- Ogg Vorbis factory functions ---
00241 #pragma mark -
00242 
00243 SeekableAudioStream *makeVorbisStream(
00244     Common::SeekableReadStream *stream,
00245     DisposeAfterUse::Flag disposeAfterUse) {
00246     SeekableAudioStream *s = new VorbisStream(stream, disposeAfterUse);
00247     if (s && s->endOfData()) {
00248         delete s;
00249         return 0;
00250     } else {
00251         return s;
00252     }
00253 }
00254 
00255 } // End of namespace Audio
00256 
00257 #endif // #ifdef USE_VORBIS


Generated on Sat May 18 2019 05:01:29 for ResidualVM by doxygen 1.7.1
curved edge   curved edge