xoreos  0.0.5
audiostream.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 /* Based on ScummVM (<http://scummvm.org>) code, which is released
26  * under the terms of version 2 or later of the GNU General Public
27  * License.
28  *
29  * The original copyright note in ScummVM reads as follows:
30  *
31  * ScummVM is the legal property of its developers, whose names
32  * are too numerous to list here. Please refer to the COPYRIGHT
33  * file distributed with this source distribution.
34  *
35  * This program is free software; you can redistribute it and/or
36  * modify it under the terms of the GNU General Public License
37  * as published by the Free Software Foundation; either version 2
38  * of the License, or (at your option) any later version.
39  *
40  * This program is distributed in the hope that it will be useful,
41  * but WITHOUT ANY WARRANTY; without even the implied warranty of
42  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43  * GNU General Public License for more details.
44  *
45  * You should have received a copy of the GNU General Public License
46  * along with this program; if not, write to the Free Software
47  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
48  */
49 
50 #include <queue>
51 
52 #include "src/common/error.h"
53 #include "src/common/mutex.h"
54 
55 #include "src/sound/audiostream.h"
56 
57 namespace Sound {
58 
59 LoopingAudioStream::LoopingAudioStream(RewindableAudioStream *stream, size_t loops, bool disposeAfterUse)
60  : _parent(stream, disposeAfterUse), _loops(loops), _completeIterations(0) {
61 }
62 
64 }
65 
66 size_t LoopingAudioStream::readBuffer(int16 *buffer, const size_t numSamples) {
67  if ((_loops && _completeIterations == _loops) || !numSamples || (_parent->getLength() == 0))
68  return 0;
69 
70  const size_t samplesRead = _parent->readBuffer(buffer, numSamples);
71  if (samplesRead == kSizeInvalid)
72  return kSizeInvalid;
73 
74  if (_parent->endOfStream()) {
77  return samplesRead;
78 
79  const size_t remainingSamples = numSamples - samplesRead;
80 
81  if (!_parent->rewind()) {
82  // TODO: Properly indicate error
84  return samplesRead;
85  }
86 
87  const size_t samplesReadNext = readBuffer(buffer + samplesRead, remainingSamples);
88  if (samplesReadNext == kSizeInvalid)
89  return kSizeInvalid;
90 
91  return samplesRead + samplesReadNext;
92  }
93 
94  return samplesRead;
95 }
96 
98  return (_loops != 0 && (_completeIterations == _loops));
99 }
100 
102  if (loops != 1)
103  return new LoopingAudioStream(stream, loops);
104  else
105  return stream;
106 }
107 
109  if (!_parent->rewind())
110  return false;
111 
113  return true;
114 }
115 
117  if (!_loops)
119 
120  uint64 length = _parent->getLength();
123 
124  return _loops * length;
125 }
126 
128  if (!_loops)
130 
131  uint64 duration = _parent->getDuration();
134 
135  return _loops * duration;
136 }
137 
139  return _parent->getLength();
140 }
141 
143  return _parent->getDuration();
144 }
145 
147 private:
155  struct StreamHolder {
158  StreamHolder(AudioStream *stream, bool disposeAfterUse)
159  : _stream(stream),
160  _disposeAfterUse(disposeAfterUse) {}
161  };
162 
166  const int _rate;
167 
171  const int _channels;
172 
176  bool _finished;
177 
183 
187  std::queue<StreamHolder> _queue;
188 
189 public:
190  QueuingAudioStreamImpl(int rate, int channels)
191  : _rate(rate), _channels(channels), _finished(false) {}
193 
194  // Implement the AudioStream API
195  virtual size_t readBuffer(int16 *buffer, const size_t numSamples);
196  virtual int getChannels() const { return _channels; }
197  virtual int getRate() const { return _rate; }
198  virtual bool endOfData() const {
200  return _queue.empty();
201  }
202  virtual bool endOfStream() const {
204  return _finished && _queue.empty();
205  }
206 
207  // Implement the QueuingAudioStream API
208  virtual void queueAudioStream(AudioStream *stream, bool disposeAfterUse);
209 
210  virtual void finish() {
212  _finished = true;
213  }
214 
215  virtual bool isFinished() const {
217  return _finished;
218  }
219 
220  size_t numQueuedStreams() const {
222  return _queue.size();
223  }
224 };
225 
227  while (!_queue.empty()) {
228  StreamHolder tmp = _queue.front();
229  _queue.pop();
230  if (tmp._disposeAfterUse)
231  delete tmp._stream;
232  }
233 }
234 
235 void QueuingAudioStreamImpl::queueAudioStream(AudioStream *stream, bool disposeAfterUse) {
236  if (_finished)
237  throw Common::Exception("QueuingAudioStreamImpl::queueAudioStream(): Trying to queue another audio stream, but the QueuingAudioStream is finished.");
238 
239  if ((stream->getRate() != getRate()) || (stream->getChannels() != getChannels()))
240  throw Common::Exception("QueuingAudioStreamImpl::queueAudioStream(): stream has mismatched parameters");
241 
243  _queue.push(StreamHolder(stream, disposeAfterUse));
244 }
245 
246 size_t QueuingAudioStreamImpl::readBuffer(int16 *buffer, const size_t numSamples) {
248  size_t samplesDecoded = 0;
249 
250  while (samplesDecoded < numSamples && !_queue.empty()) {
251  AudioStream *stream = _queue.front()._stream;
252 
253  const size_t n = stream->readBuffer(buffer + samplesDecoded, numSamples - samplesDecoded);
254  if (n == kSizeInvalid)
255  return kSizeInvalid;
256 
257  samplesDecoded += n;
258 
259  if (stream->endOfData()) {
260  StreamHolder tmp = _queue.front();
261  _queue.pop();
262  if (tmp._disposeAfterUse)
263  delete stream;
264  }
265  }
266 
267  return samplesDecoded;
268 }
269 
270 QueuingAudioStream *makeQueuingAudioStream(int rate, int channels) {
271  return new QueuingAudioStreamImpl(rate, channels);
272 }
273 
274 } // End of namespace Sound
const int _channels
The number of channels in this audio stream.
Common::Mutex _mutex
A mutex to avoid access problems (causing e.g.
uint64 getDuration() const
QueuingAudioStream * makeQueuingAudioStream(int rate, int channels)
Factory function for an QueuingAudioStream.
size_t numQueuedStreams() const
Return the number of streams still queued for playback (including the currently playing stream)...
We queue a number of (pointers to) audio stream objects.
StreamHolder(AudioStream *stream, bool disposeAfterUse)
uint64_t uint64
Definition: types.h:206
uint64 getDurationOnce() const
Return the duration of one loop.
virtual int getChannels() const =0
Return the number channels in this stream.
virtual size_t readBuffer(int16 *buffer, const size_t numSamples)
Fill the given buffer with up to numSamples samples.
virtual int getRate() const =0
Sample rate of the stream.
A looping audio stream.
Definition: audiostream.h:175
int16_t int16
Definition: types.h:201
Common::DisposablePtr< RewindableAudioStream > _parent
Definition: audiostream.h:209
virtual bool isFinished() const
Is the stream marked as finished?
bool endOfData() const
End of data reached? If this returns true, it means that at this time there is no data available in t...
Definition: audiostream.cpp:97
Definition: game.h:37
virtual int getChannels() const
Return the number channels in this stream.
LoopingAudioStream(RewindableAudioStream *stream, size_t loops, bool disposeAfterUse=true)
Creates a looping audio stream object.
Definition: audiostream.cpp:59
virtual void finish()
Mark this stream as finished.
Basic exceptions to throw.
A rewindable audio stream.
Definition: audiostream.h:125
A mutex.
Definition: mutex.h:40
size_t readBuffer(int16 *buffer, const size_t numSamples)
Fill the given buffer with up to numSamples samples.
Definition: audiostream.cpp:66
virtual size_t readBuffer(int16 *buffer, const size_t numSamples)=0
Fill the given buffer with up to numSamples samples.
static const size_t kSizeInvalid
Definition: audiostream.h:72
static const uint64 kInvalidLength
Definition: audiostream.h:127
std::queue< StreamHolder > _queue
The queue of audio streams.
StackException Exception
Definition: error.h:59
Convenience class that locks a mutex on creation and unlocks it on destruction.
Definition: mutex.h:71
Thread mutex classes.
Generic audio input stream.
Definition: audiostream.h:70
virtual int getRate() const
Sample rate of the stream.
virtual void queueAudioStream(AudioStream *stream, bool disposeAfterUse)
Queue an audio stream for playback.
QueuingAudioStreamImpl(int rate, int channels)
AudioStream * makeLoopingAudioStream(RewindableAudioStream *stream, size_t loops)
Wrapper functionality to efficiently create a stream, which might be looped.
virtual bool endOfStream() const
End of stream reached? If this returns true, it means that all data in this stream is used up and no ...
bool _finished
This flag is set by the finish() method only.
uint64 getLengthOnce() const
Return the length of one loop.
const int _rate
The sampling rate of this audio stream.
Streaming audio.
virtual bool endOfData() const =0
End of data reached? If this returns true, it means that at this time there is no data available in t...
virtual bool endOfData() const
End of data reached? If this returns true, it means that at this time there is no data available in t...