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

audiocd-stream.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  * Original license header:
00022  *
00023  * Cabal - Legacy Game Implementations
00024  *
00025  * Cabal is the legal property of its developers, whose names
00026  * are too numerous to list here. Please refer to the COPYRIGHT
00027  * file distributed with this source distribution.
00028  *
00029  * This program is free software; you can redistribute it and/or
00030  * modify it under the terms of the GNU General Public License
00031  * as published by the Free Software Foundation; either version 2
00032  * of the License, or (at your option) any later version.
00033  *
00034  * This program is distributed in the hope that it will be useful,
00035  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00036  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00037  * GNU General Public License for more details.
00038  *
00039  * You should have received a copy of the GNU General Public License
00040  * along with this program; if not, write to the Free Software
00041  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00042  *
00043  */
00044 
00045 #include "backends/audiocd/audiocd-stream.h"
00046 #include "common/textconsole.h"
00047 
00048 AudioCDStream::AudioCDStream() : _buffer(), _frame(0), _bufferPos(0), _bufferFrame(0), _forceStop(false) {
00049 }
00050 
00051 AudioCDStream::~AudioCDStream() {
00052     // Stop the timer; the subclass needs to do this,
00053     // so this is just a last resort.
00054     stopTimer();
00055 
00056     // Clear any buffered frames
00057     emptyQueue();
00058 }
00059 
00060 int AudioCDStream::readBuffer(int16 *buffer, const int numSamples) {
00061     int samples = 0;
00062 
00063     // See if any data is left first
00064     while (_bufferPos < kSamplesPerFrame && samples < numSamples)
00065         buffer[samples++] = _buffer[_bufferPos++];
00066 
00067     // Bail out if done
00068     if (endOfData())
00069         return samples;
00070 
00071     while (samples < numSamples && !endOfData()) {
00072         if (!readNextFrame())
00073             return samples;
00074 
00075         // Copy the samples over
00076         for (_bufferPos = 0; _bufferPos < kSamplesPerFrame && samples < numSamples;)
00077             buffer[samples++] = _buffer[_bufferPos++];
00078     }
00079 
00080     return samples;
00081 }
00082 
00083 bool AudioCDStream::readNextFrame() {
00084     // Fetch a frame from the queue
00085     int16 *buffer;
00086 
00087     {
00088         Common::StackLock lock(_mutex);
00089 
00090         // Nothing we can do if it's empty
00091         if (_bufferQueue.empty())
00092             return false;
00093 
00094         buffer = _bufferQueue.pop();
00095     }
00096 
00097     memcpy(_buffer, buffer, kSamplesPerFrame * 2);
00098     delete[] buffer;
00099     _frame++;
00100     return true;
00101 }
00102 
00103 bool AudioCDStream::endOfData() const {
00104     return !shouldForceStop() && getStartFrame() + _frame >= getEndFrame() && _bufferPos == kSamplesPerFrame;
00105 }
00106 
00107 bool AudioCDStream::seek(const Audio::Timestamp &where) {
00108     // Stop the timer
00109     stopTimer();
00110 
00111     // Clear anything out of the queue
00112     emptyQueue();
00113 
00114     // Convert to the frame number
00115     // Really not much else needed
00116     _bufferPos = kSamplesPerFrame;
00117     _frame = where.convertToFramerate(kFramesPerSecond).totalNumberOfFrames();
00118     _bufferFrame = _frame;
00119 
00120     // Start the timer again
00121     startTimer();
00122     return true;
00123 }
00124 
00125 Audio::Timestamp AudioCDStream::getLength() const {
00126     return Audio::Timestamp(0, getEndFrame() - getStartFrame(), kFramesPerSecond);
00127 }
00128 
00129 void AudioCDStream::timerProc(void *refCon) {
00130     static_cast<AudioCDStream *>(refCon)->onTimer();
00131 }
00132 
00133 void AudioCDStream::onTimer() {
00134     // The goal here is to do as much work in this timer instead
00135     // of doing it in the readBuffer() call, which is the mixer.
00136 
00137     // If we're done, bail.
00138     if (shouldForceStop() || getStartFrame() + _bufferFrame >= getEndFrame())
00139         return;
00140 
00141     // Get a quick count of the number of items in the queue
00142     // We don't care that much; we only need a quick estimate
00143     _mutex.lock();
00144     uint32 queueCount = _bufferQueue.size();
00145     _mutex.unlock();
00146 
00147     // If we have enough audio buffered, bail out
00148     if (queueCount >= kBufferThreshold)
00149         return;
00150 
00151     while (!shouldForceStop() && queueCount < kBufferThreshold && getStartFrame() + _bufferFrame < getEndFrame()) {
00152         int16 *buffer = new int16[kSamplesPerFrame];
00153 
00154         // Figure out the MSF of the frame we're looking for
00155         int frame = _bufferFrame + getStartFrame();
00156 
00157         // Request to read that frame
00158         if (!readFrame(frame, buffer)) {
00159             warning("Failed to read CD audio");
00160             forceStop();
00161             return;
00162         }
00163 
00164         _bufferFrame++;
00165 
00166         // Now push the buffer onto the queue
00167         Common::StackLock lock(_mutex);
00168         _bufferQueue.push(buffer);
00169         queueCount = _bufferQueue.size();
00170     }
00171 }
00172 
00173 void AudioCDStream::startTimer(bool fillBuffer) {
00174     _forceStop = false;
00175     if (fillBuffer) {
00176         onTimer();
00177     }
00178     g_system->getTimerManager()->installTimerProc(timerProc, 10 * 1000, this, "AudioCDStream");
00179 }
00180 
00181 void AudioCDStream::stopTimer() {
00182     forceStop();
00183     g_system->getTimerManager()->removeTimerProc(timerProc);
00184 }
00185 
00186 void AudioCDStream::emptyQueue() {
00187     while (!_bufferQueue.empty())
00188         delete[] _bufferQueue.pop();
00189 }
00190 
00191 bool AudioCDStream::shouldForceStop() const {
00192     Common::StackLock lock(_forceStopMutex);
00193     return _forceStop;
00194 }
00195 
00196 void AudioCDStream::forceStop() {
00197     Common::StackLock lock(_forceStopMutex);
00198     _forceStop = true;
00199 }


Generated on Sat Aug 17 2019 05:00:25 for ResidualVM by doxygen 1.7.1
curved edge   curved edge