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

audiostream.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 #include "common/debug.h"
00024 #include "common/file.h"
00025 #include "common/mutex.h"
00026 #include "common/textconsole.h"
00027 #include "common/queue.h"
00028 #include "common/util.h"
00029 
00030 #include "audio/audiostream.h"
00031 #include "audio/decoders/flac.h"
00032 #include "audio/decoders/mp3.h"
00033 #include "audio/decoders/quicktime.h"
00034 #include "audio/decoders/raw.h"
00035 #include "audio/decoders/vorbis.h"
00036 #include "audio/mixer.h"
00037 
00038 
00039 namespace Audio {
00040 
00041 struct StreamFileFormat {
00043     const char *decoderName;
00044     const char *fileExtension;
00049     SeekableAudioStream *(*openStreamFile)(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse);
00050 };
00051 
00052 static const StreamFileFormat STREAM_FILEFORMATS[] = {
00053     /* decoderName,  fileExt, openStreamFunction */
00054 #ifdef USE_FLAC
00055     { "FLAC",         ".flac", makeFLACStream },
00056     { "FLAC",         ".fla",  makeFLACStream },
00057 #endif
00058 #ifdef USE_VORBIS
00059     { "Ogg Vorbis",   ".ogg",  makeVorbisStream },
00060 #endif
00061 #ifdef USE_MAD
00062     { "MPEG Layer 3", ".mp3",  makeMP3Stream },
00063 #endif
00064     { "MPEG-4 Audio",   ".m4a",  makeQuickTimeStream },
00065 };
00066 
00067 SeekableAudioStream *SeekableAudioStream::openStreamFile(const Common::String &basename) {
00068     SeekableAudioStream *stream = NULL;
00069     Common::File *fileHandle = new Common::File();
00070 
00071     for (int i = 0; i < ARRAYSIZE(STREAM_FILEFORMATS); ++i) {
00072         Common::String filename = basename + STREAM_FILEFORMATS[i].fileExtension;
00073         fileHandle->open(filename);
00074         if (fileHandle->isOpen()) {
00075             // Create the stream object
00076             stream = STREAM_FILEFORMATS[i].openStreamFile(fileHandle, DisposeAfterUse::YES);
00077             fileHandle = 0;
00078             break;
00079         }
00080     }
00081 
00082     delete fileHandle;
00083 
00084     if (stream == NULL)
00085         debug(1, "SeekableAudioStream::openStreamFile: Could not open compressed AudioFile %s", basename.c_str());
00086 
00087     return stream;
00088 }
00089 
00090 #pragma mark -
00091 #pragma mark --- LoopingAudioStream ---
00092 #pragma mark -
00093 
00094 LoopingAudioStream::LoopingAudioStream(RewindableAudioStream *stream, uint loops, DisposeAfterUse::Flag disposeAfterUse)
00095     : _parent(stream, disposeAfterUse), _loops(loops), _completeIterations(0) {
00096     assert(stream);
00097 
00098     if (!stream->rewind()) {
00099         // TODO: Properly indicate error
00100         _loops = _completeIterations = 1;
00101     }
00102     if (stream->endOfStream()) {
00103         // Apparently this is an empty stream
00104         _loops = _completeIterations = 1;
00105     }
00106 }
00107 
00108 int LoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
00109     if ((_loops && _completeIterations == _loops) || !numSamples)
00110         return 0;
00111 
00112     int samplesRead = _parent->readBuffer(buffer, numSamples);
00113 
00114     if (_parent->endOfStream()) {
00115         ++_completeIterations;
00116         if (_completeIterations == _loops)
00117             return samplesRead;
00118 
00119         const int remainingSamples = numSamples - samplesRead;
00120 
00121         if (!_parent->rewind()) {
00122             // TODO: Properly indicate error
00123             _loops = _completeIterations = 1;
00124             return samplesRead;
00125         }
00126         if (_parent->endOfStream()) {
00127             // Apparently this is an empty stream
00128             _loops = _completeIterations = 1;
00129         }
00130 
00131         return samplesRead + readBuffer(buffer + samplesRead, remainingSamples);
00132     }
00133 
00134     return samplesRead;
00135 }
00136 
00137 bool LoopingAudioStream::endOfData() const {
00138     return (_loops != 0 && _completeIterations == _loops) || _parent->endOfData();
00139 }
00140 
00141 bool LoopingAudioStream::endOfStream() const {
00142     return _loops != 0 && _completeIterations == _loops;
00143 }
00144 
00145 AudioStream *makeLoopingAudioStream(RewindableAudioStream *stream, uint loops) {
00146     if (loops != 1)
00147         return new LoopingAudioStream(stream, loops);
00148     else
00149         return stream;
00150 }
00151 
00152 AudioStream *makeLoopingAudioStream(SeekableAudioStream *stream, Timestamp start, Timestamp end, uint loops) {
00153     if (!start.totalNumberOfFrames() && (!end.totalNumberOfFrames() || end == stream->getLength())) {
00154         return makeLoopingAudioStream(stream, loops);
00155     } else {
00156         if (!end.totalNumberOfFrames())
00157             end = stream->getLength();
00158 
00159         if (start >= end) {
00160             warning("makeLoopingAudioStream: start (%d) >= end (%d)", start.msecs(), end.msecs());
00161             delete stream;
00162             return 0;
00163         }
00164 
00165         return makeLoopingAudioStream(new SubSeekableAudioStream(stream, start, end), loops);
00166     }
00167 }
00168 
00169 #pragma mark -
00170 #pragma mark --- SubLoopingAudioStream ---
00171 #pragma mark -
00172 
00173 SubLoopingAudioStream::SubLoopingAudioStream(SeekableAudioStream *stream,
00174                                              uint loops,
00175                                              const Timestamp loopStart,
00176                                              const Timestamp loopEnd,
00177                                              DisposeAfterUse::Flag disposeAfterUse)
00178     : _parent(stream, disposeAfterUse), _loops(loops),
00179       _pos(0, getRate() * (isStereo() ? 2 : 1)),
00180       _loopStart(convertTimeToStreamPos(loopStart, getRate(), isStereo())),
00181       _loopEnd(convertTimeToStreamPos(loopEnd, getRate(), isStereo())),
00182       _done(false) {
00183     assert(loopStart < loopEnd);
00184 
00185     if (!_parent->rewind())
00186         _done = true;
00187 }
00188 
00189 int SubLoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
00190     if (_done)
00191         return 0;
00192 
00193     int framesLeft = MIN(_loopEnd.frameDiff(_pos), numSamples);
00194     int framesRead = _parent->readBuffer(buffer, framesLeft);
00195     _pos = _pos.addFrames(framesRead);
00196 
00197     if (framesRead < framesLeft && _parent->endOfStream()) {
00198         // TODO: Proper error indication.
00199         _done = true;
00200         return framesRead;
00201     } else if (_pos == _loopEnd) {
00202         if (_loops != 0) {
00203             --_loops;
00204             if (!_loops) {
00205                 _done = true;
00206                 return framesRead;
00207             }
00208         }
00209 
00210         if (!_parent->seek(_loopStart)) {
00211             // TODO: Proper error indication.
00212             _done = true;
00213             return framesRead;
00214         }
00215 
00216         _pos = _loopStart;
00217         framesLeft = numSamples - framesLeft;
00218         return framesRead + readBuffer(buffer + framesRead, framesLeft);
00219     } else {
00220         return framesRead;
00221     }
00222 }
00223 
00224 bool SubLoopingAudioStream::endOfData() const {
00225     // We're out of data if this stream is finished or the parent
00226     // has run out of data for now.
00227     return _done || _parent->endOfData();
00228 }
00229 
00230 bool SubLoopingAudioStream::endOfStream() const {
00231     // The end of the stream has been reached only when we've gone
00232     // through all the iterations.
00233     return _done;
00234 }
00235 
00236 #pragma mark -
00237 #pragma mark --- SubSeekableAudioStream ---
00238 #pragma mark -
00239 
00240 SubSeekableAudioStream::SubSeekableAudioStream(SeekableAudioStream *parent, const Timestamp start, const Timestamp end, DisposeAfterUse::Flag disposeAfterUse)
00241     : _parent(parent, disposeAfterUse),
00242       _start(convertTimeToStreamPos(start, getRate(), isStereo())),
00243       _pos(0, getRate() * (isStereo() ? 2 : 1)),
00244       _length(convertTimeToStreamPos(end, getRate(), isStereo()) - _start) {
00245 
00246     assert(_length.totalNumberOfFrames() % (isStereo() ? 2 : 1) == 0);
00247     _parent->seek(_start);
00248 }
00249 
00250 int SubSeekableAudioStream::readBuffer(int16 *buffer, const int numSamples) {
00251     int framesLeft = MIN(_length.frameDiff(_pos), numSamples);
00252     int framesRead = _parent->readBuffer(buffer, framesLeft);
00253     _pos = _pos.addFrames(framesRead);
00254     return framesRead;
00255 }
00256 
00257 bool SubSeekableAudioStream::seek(const Timestamp &where) {
00258     _pos = convertTimeToStreamPos(where, getRate(), isStereo());
00259     if (_pos > _length) {
00260         _pos = _length;
00261         return false;
00262     }
00263 
00264     if (_parent->seek(_pos + _start)) {
00265         return true;
00266     } else {
00267         _pos = _length;
00268         return false;
00269     }
00270 }
00271 
00272 #pragma mark -
00273 #pragma mark --- Queueing audio stream ---
00274 #pragma mark -
00275 
00276 
00277 void QueuingAudioStream::queueBuffer(byte *data, uint32 size, DisposeAfterUse::Flag disposeAfterUse, byte flags) {
00278     AudioStream *stream = makeRawStream(data, size, getRate(), flags, disposeAfterUse);
00279     queueAudioStream(stream, DisposeAfterUse::YES);
00280 }
00281 
00282 
00283 class QueuingAudioStreamImpl : public QueuingAudioStream {
00284 private:
00292     struct StreamHolder {
00293         AudioStream *_stream;
00294         DisposeAfterUse::Flag _disposeAfterUse;
00295         StreamHolder(AudioStream *stream, DisposeAfterUse::Flag disposeAfterUse)
00296             : _stream(stream),
00297               _disposeAfterUse(disposeAfterUse) {}
00298     };
00299 
00303     const int _rate;
00304 
00308     const int _stereo;
00309 
00313     bool _finished;
00314 
00319     Common::Mutex _mutex;
00320 
00324     Common::Queue<StreamHolder> _queue;
00325 
00326 public:
00327     QueuingAudioStreamImpl(int rate, bool stereo)
00328         : _rate(rate), _stereo(stereo), _finished(false) {}
00329     ~QueuingAudioStreamImpl();
00330 
00331     // Implement the AudioStream API
00332     virtual int readBuffer(int16 *buffer, const int numSamples);
00333     virtual bool isStereo() const { return _stereo; }
00334     virtual int getRate() const { return _rate; }
00335 
00336     virtual bool endOfData() const {
00337         Common::StackLock lock(_mutex);
00338         return _queue.empty() || _queue.front()._stream->endOfData();
00339     }
00340 
00341     virtual bool endOfStream() const {
00342         Common::StackLock lock(_mutex);
00343         return _finished && _queue.empty();
00344     }
00345 
00346     // Implement the QueuingAudioStream API
00347     virtual void queueAudioStream(AudioStream *stream, DisposeAfterUse::Flag disposeAfterUse);
00348 
00349     virtual void finish() {
00350         Common::StackLock lock(_mutex);
00351         _finished = true;
00352     }
00353 
00354     uint32 numQueuedStreams() const {
00355         Common::StackLock lock(_mutex);
00356         return _queue.size();
00357     }
00358 };
00359 
00360 QueuingAudioStreamImpl::~QueuingAudioStreamImpl() {
00361     while (!_queue.empty()) {
00362         StreamHolder tmp = _queue.pop();
00363         if (tmp._disposeAfterUse == DisposeAfterUse::YES)
00364             delete tmp._stream;
00365     }
00366 }
00367 
00368 void QueuingAudioStreamImpl::queueAudioStream(AudioStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
00369     assert(!_finished);
00370     if ((stream->getRate() != getRate()) || (stream->isStereo() != isStereo()))
00371         error("QueuingAudioStreamImpl::queueAudioStream: stream has mismatched parameters");
00372 
00373     Common::StackLock lock(_mutex);
00374     _queue.push(StreamHolder(stream, disposeAfterUse));
00375 }
00376 
00377 int QueuingAudioStreamImpl::readBuffer(int16 *buffer, const int numSamples) {
00378     Common::StackLock lock(_mutex);
00379     int samplesDecoded = 0;
00380 
00381     while (samplesDecoded < numSamples && !_queue.empty()) {
00382         AudioStream *stream = _queue.front()._stream;
00383         samplesDecoded += stream->readBuffer(buffer + samplesDecoded, numSamples - samplesDecoded);
00384 
00385         // Done with the stream completely
00386         if (stream->endOfStream()) {
00387             StreamHolder tmp = _queue.pop();
00388             if (tmp._disposeAfterUse == DisposeAfterUse::YES)
00389                 delete stream;
00390             continue;
00391         }
00392 
00393         // Done with data but not the stream, bail out
00394         if (stream->endOfData())
00395             break;
00396     }
00397 
00398     return samplesDecoded;
00399 }
00400 
00401 QueuingAudioStream *makeQueuingAudioStream(int rate, bool stereo) {
00402     return new QueuingAudioStreamImpl(rate, stereo);
00403 }
00404 
00405 Timestamp convertTimeToStreamPos(const Timestamp &where, int rate, bool isStereo) {
00406     Timestamp result(where.convertToFramerate(rate * (isStereo ? 2 : 1)));
00407 
00408     // When the Stream is a stereo stream, we have to assure
00409     // that the sample position is an even number.
00410     if (isStereo && (result.totalNumberOfFrames() & 1))
00411         result = result.addFrames(-1); // We cut off one sample here.
00412 
00413     // Since Timestamp allows sub-frame-precision it might lead to odd behaviors
00414     // when we would just return result.
00415     //
00416     // An example is when converting the timestamp 500ms to a 11025 Hz based
00417     // stream. It would have an internal frame counter of 5512.5. Now when
00418     // doing calculations at frame precision, this might lead to unexpected
00419     // results: The frame difference between a timestamp 1000ms and the above
00420     // mentioned timestamp (both with 11025 as framerate) would be 5512,
00421     // instead of 5513, which is what a frame-precision based code would expect.
00422     //
00423     // By creating a new Timestamp with the given parameters, we create a
00424     // Timestamp with frame-precision, which just drops a sub-frame-precision
00425     // information (i.e. rounds down).
00426     return Timestamp(result.secs(), result.numberOfFrames(), result.framerate());
00427 }
00428 
00433 class LimitingAudioStream : public AudioStream {
00434 public:
00435     LimitingAudioStream(AudioStream *parentStream, const Audio::Timestamp &length, DisposeAfterUse::Flag disposeAfterUse) :
00436             _parentStream(parentStream), _samplesRead(0), _disposeAfterUse(disposeAfterUse),
00437             _totalSamples(length.convertToFramerate(getRate()).totalNumberOfFrames() * getChannels()) {}
00438 
00439     ~LimitingAudioStream() {
00440         if (_disposeAfterUse == DisposeAfterUse::YES)
00441             delete _parentStream;
00442     }
00443 
00444     int readBuffer(int16 *buffer, const int numSamples) {
00445         // Cap us off so we don't read past _totalSamples
00446         int samplesRead = _parentStream->readBuffer(buffer, MIN<int>(numSamples, _totalSamples - _samplesRead));
00447         _samplesRead += samplesRead;
00448         return samplesRead;
00449     }
00450 
00451     bool endOfData() const { return _parentStream->endOfData() || reachedLimit(); }
00452     bool endOfStream() const { return _parentStream->endOfStream() || reachedLimit(); }
00453     bool isStereo() const { return _parentStream->isStereo(); }
00454     int getRate() const { return _parentStream->getRate(); }
00455 
00456 private:
00457     int getChannels() const { return isStereo() ? 2 : 1; }
00458     bool reachedLimit() const { return _samplesRead >= _totalSamples; }
00459 
00460     AudioStream *_parentStream;
00461     DisposeAfterUse::Flag _disposeAfterUse;
00462     uint32 _totalSamples, _samplesRead;
00463 };
00464 
00465 AudioStream *makeLimitingAudioStream(AudioStream *parentStream, const Timestamp &length, DisposeAfterUse::Flag disposeAfterUse) {
00466     return new LimitingAudioStream(parentStream, length, disposeAfterUse);
00467 }
00468 
00473 class NullAudioStream : public AudioStream {
00474 public:
00475         bool isStereo() const { return false; }
00476         int getRate() const;
00477         int readBuffer(int16 *data, const int numSamples) { return 0; }
00478         bool endOfData() const { return true; }
00479 };
00480 
00481 int NullAudioStream::getRate() const {
00482     return g_system->getMixer()->getOutputRate();
00483 }
00484 
00485 AudioStream *makeNullAudioStream() {
00486     return new NullAudioStream();
00487 }
00488 
00489 } // End of namespace Audio


Generated on Sat Feb 23 2019 05:00:57 for ResidualVM by doxygen 1.7.1
curved edge   curved edge