1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program 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 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program 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 this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "common/endian.h"
24 #include "common/memstream.h"
25 #include "common/textconsole.h"
26 #include "common/util.h"
27
28 #include "audio/audiostream.h"
29 #include "audio/decoders/raw.h"
30
31 namespace Audio {
32
33 #pragma mark -
34 #pragma mark --- RawStream ---
35 #pragma mark -
36
37 /**
38 * This is a stream, which allows for playing raw PCM data from a stream.
39 */
40 template<int bytesPerSample, bool isUnsigned, bool isLE>
41 class RawStream : public SeekableAudioStream {
42 public:
RawStream(int rate,bool stereo,DisposeAfterUse::Flag disposeStream,Common::SeekableReadStream * stream)43 RawStream(int rate, bool stereo, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream)
44 : _rate(rate), _isStereo(stereo), _playtime(0, rate), _stream(stream, disposeStream), _endOfData(false), _buffer(0) {
45 // Setup our buffer for readBuffer
46 _buffer = new byte[kSampleBufferLength * bytesPerSample];
47 assert(_buffer);
48
49 // Calculate the total playtime of the stream
50 _playtime = Timestamp(0, _stream->size() / (_isStereo ? 2 : 1) / bytesPerSample, rate);
51 }
52
~RawStream()53 ~RawStream() {
54 delete[] _buffer;
55 }
56
57 int readBuffer(int16 *buffer, const int numSamples);
58
isStereo() const59 bool isStereo() const { return _isStereo; }
endOfData() const60 bool endOfData() const { return _endOfData; }
61
getRate() const62 int getRate() const { return _rate; }
getLength() const63 Timestamp getLength() const { return _playtime; }
64
65 bool seek(const Timestamp &where);
66 private:
67 const int _rate; ///< Sample rate of stream
68 const bool _isStereo; ///< Whether this is an stereo stream
69 Timestamp _playtime; ///< Calculated total play time
70 Common::DisposablePtr<Common::SeekableReadStream> _stream; ///< Stream to read data from
71 bool _endOfData; ///< Whether the stream end has been reached
72
73 byte *_buffer; ///< Buffer used in readBuffer
74 enum {
75 /**
76 * How many samples we can buffer at once.
77 *
78 * TODO: Check whether this size suffices
79 * for systems with slow disk I/O.
80 */
81 kSampleBufferLength = 2048
82 };
83
84 /**
85 * Fill the temporary sample buffer used in readBuffer.
86 *
87 * @param maxSamples Maximum samples to read.
88 * @return actual count of samples read.
89 */
90 int fillBuffer(int maxSamples);
91 };
92
93 template<int bytesPerSample, bool isUnsigned, bool isLE>
readBuffer(int16 * buffer,const int numSamples)94 int RawStream<bytesPerSample, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
95 int samplesLeft = numSamples;
96
97 while (samplesLeft > 0) {
98 // Try to read up to "samplesLeft" samples.
99 int len = fillBuffer(samplesLeft);
100
101 // In case we were not able to read any samples
102 // we will stop reading here.
103 if (!len)
104 break;
105
106 // Adjust the samples left to read.
107 samplesLeft -= len;
108
109 // Copy the data to the caller's buffer.
110 const byte *src = _buffer;
111 while (len-- > 0) {
112 if (bytesPerSample == 1)
113 *buffer++ = (*src << 8) ^ (isUnsigned ? 0x8000 : 0);
114 else if (bytesPerSample == 2)
115 *buffer++ = ((isLE ? READ_LE_UINT16(src) : READ_BE_UINT16(src)) ^ (isUnsigned ? 0x8000 : 0));
116 else // if (bytesPerSample == 3)
117 *buffer++ = (((int16)((isLE ? READ_LE_UINT24(src) : READ_BE_UINT24(src)) >> 8)) ^ (isUnsigned ? 0x8000 : 0));
118
119 src += bytesPerSample;
120 }
121 }
122
123 return numSamples - samplesLeft;
124 }
125
126 template<int bytesPerSample, bool isUnsigned, bool isLE>
fillBuffer(int maxSamples)127 int RawStream<bytesPerSample, isUnsigned, isLE>::fillBuffer(int maxSamples) {
128 int bufferedSamples = 0;
129 byte *dst = _buffer;
130
131 // We can only read up to "kSampleBufferLength" samples
132 // so we take this into consideration, when trying to
133 // read up to maxSamples.
134 maxSamples = MIN<int>(kSampleBufferLength, maxSamples);
135
136 // We will only read up to maxSamples
137 while (maxSamples > 0 && !endOfData()) {
138 // Try to read all the sample data and update the
139 // destination pointer.
140 const int bytesRead = _stream->read(dst, maxSamples * bytesPerSample);
141 dst += bytesRead;
142
143 // Calculate how many samples we actually read.
144 const int samplesRead = bytesRead / bytesPerSample;
145
146 // Update all status variables
147 bufferedSamples += samplesRead;
148 maxSamples -= samplesRead;
149
150 // We stop stream playback, when we reached the end of the data stream.
151 // We also stop playback when an error occures.
152 if (_stream->pos() == _stream->size() || _stream->err() || _stream->eos())
153 _endOfData = true;
154 }
155
156 return bufferedSamples;
157 }
158
159 template<int bytesPerSample, bool isUnsigned, bool isLE>
seek(const Timestamp & where)160 bool RawStream<bytesPerSample, isUnsigned, isLE>::seek(const Timestamp &where) {
161 _endOfData = true;
162
163 if (where > _playtime)
164 return false;
165
166 const uint32 seekSample = convertTimeToStreamPos(where, getRate(), isStereo()).totalNumberOfFrames();
167 _stream->seek(seekSample * bytesPerSample, SEEK_SET);
168
169 // In case of an error we will not continue stream playback.
170 if (!_stream->err() && !_stream->eos() && _stream->pos() != _stream->size())
171 _endOfData = false;
172
173 return true;
174 }
175
176 #pragma mark -
177 #pragma mark --- Raw stream factories ---
178 #pragma mark -
179
180 /* In the following, we use preprocessor / macro tricks to simplify the code
181 * which instantiates the input streams. We used to use template functions for
182 * this, but MSVC6 / EVC 3-4 (used for WinCE builds) are extremely buggy when it
183 * comes to this feature of C++... so as a compromise we use macros to cut down
184 * on the (source) code duplication a bit.
185 * So while normally macro tricks are said to make maintenance harder, in this
186 * particular case it should actually help it :-)
187 */
188
189 #define MAKE_RAW_STREAM(UNSIGNED) \
190 if (bytesPerSample == 3) { \
191 if (isLE) \
192 return new RawStream<3, UNSIGNED, true>(rate, isStereo, disposeAfterUse, stream); \
193 else \
194 return new RawStream<3, UNSIGNED, false>(rate, isStereo, disposeAfterUse, stream); \
195 } else if (bytesPerSample == 2) { \
196 if (isLE) \
197 return new RawStream<2, UNSIGNED, true>(rate, isStereo, disposeAfterUse, stream); \
198 else \
199 return new RawStream<2, UNSIGNED, false>(rate, isStereo, disposeAfterUse, stream); \
200 } else \
201 return new RawStream<1, UNSIGNED, false>(rate, isStereo, disposeAfterUse, stream)
202
makeRawStream(Common::SeekableReadStream * stream,int rate,byte flags,DisposeAfterUse::Flag disposeAfterUse)203 SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream,
204 int rate, byte flags,
205 DisposeAfterUse::Flag disposeAfterUse) {
206 const bool isStereo = (flags & Audio::FLAG_STEREO) != 0;
207 const int bytesPerSample = (flags & Audio::FLAG_24BITS ? 3 : (flags & Audio::FLAG_16BITS ? 2 : 1));
208 const bool isUnsigned = (flags & Audio::FLAG_UNSIGNED) != 0;
209 const bool isLE = (flags & Audio::FLAG_LITTLE_ENDIAN) != 0;
210
211 assert(stream->size() % (bytesPerSample * (isStereo ? 2 : 1)) == 0);
212
213 if (isUnsigned) {
214 MAKE_RAW_STREAM(true);
215 } else {
216 MAKE_RAW_STREAM(false);
217 }
218 }
219
makeRawStream(const byte * buffer,uint32 size,int rate,byte flags,DisposeAfterUse::Flag disposeAfterUse)220 SeekableAudioStream *makeRawStream(const byte *buffer, uint32 size,
221 int rate, byte flags,
222 DisposeAfterUse::Flag disposeAfterUse) {
223 return makeRawStream(new Common::MemoryReadStream(buffer, size, disposeAfterUse), rate, flags, DisposeAfterUse::YES);
224 }
225
226 class PacketizedRawStream : public StatelessPacketizedAudioStream {
227 public:
PacketizedRawStream(int rate,byte flags)228 PacketizedRawStream(int rate, byte flags) :
229 StatelessPacketizedAudioStream(rate, ((flags & FLAG_STEREO) != 0) ? 2 : 1), _flags(flags) {}
230
231 protected:
232 AudioStream *makeStream(Common::SeekableReadStream *data);
233
234 private:
235 byte _flags;
236 };
237
makeStream(Common::SeekableReadStream * data)238 AudioStream *PacketizedRawStream::makeStream(Common::SeekableReadStream *data) {
239 return makeRawStream(data, getRate(), _flags);
240 }
241
makePacketizedRawStream(int rate,byte flags)242 PacketizedAudioStream *makePacketizedRawStream(int rate, byte flags) {
243 return new PacketizedRawStream(rate, flags);
244 }
245
246 } // End of namespace Audio
247