0x47 stub
[scummvm-innocent.git] / sound / vorbis.cpp
blob8b8bb8f649fc90ba59b72bc5b3dceb5df843e847
1 /* ScummVM - Graphic Adventure Engine
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.
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.
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.
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.
21 * $URL$
22 * $Id$
26 #include "sound/vorbis.h"
28 #ifdef USE_VORBIS
30 #include "common/debug.h"
31 #include "common/stream.h"
32 #include "common/util.h"
34 #include "sound/audiostream.h"
35 #include "sound/audiocd.h"
37 #ifdef USE_TREMOR
38 #ifdef __GP32__ // GP32 uses custom libtremor
39 #include <ivorbisfile.h>
40 #else
41 #include <tremor/ivorbisfile.h>
42 #endif
43 #else
44 #include <vorbis/vorbisfile.h>
45 #endif
48 namespace Audio {
50 // These are wrapper functions to allow using a SeekableReadStream object to
51 // provide data to the OggVorbis_File object.
53 static size_t read_stream_wrap(void *ptr, size_t size, size_t nmemb, void *datasource) {
54 Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource;
56 uint32 result = stream->read(ptr, size * nmemb);
58 return result / size;
61 static int seek_stream_wrap(void *datasource, ogg_int64_t offset, int whence) {
62 Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource;
63 stream->seek((int32)offset, whence);
64 return stream->pos();
67 static int close_stream_wrap(void *datasource) {
68 // Do nothing -- we leave it up to the VorbisInputStream to free memory as appropriate.
69 return 0;
72 static long tell_stream_wrap(void *datasource) {
73 Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource;
74 return stream->pos();
77 static ov_callbacks g_stream_wrap = {
78 read_stream_wrap, seek_stream_wrap, close_stream_wrap, tell_stream_wrap
83 #pragma mark -
84 #pragma mark --- Ogg Vorbis stream ---
85 #pragma mark -
88 class VorbisInputStream : public AudioStream {
89 protected:
90 Common::SeekableReadStream *_inStream;
91 bool _disposeAfterUse;
93 bool _isStereo;
94 int _rate;
95 uint _numLoops;
96 const uint _totalNumLoops;
98 #ifdef USE_TREMOR
99 ogg_int64_t _startTime;
100 ogg_int64_t _endTime;
101 #else
102 double _startTime;
103 double _endTime;
104 #endif
106 OggVorbis_File _ovFile;
108 int16 _buffer[4096];
109 const int16 *_bufferEnd;
110 const int16 *_pos;
112 public:
113 // startTime / duration are in milliseconds
114 VorbisInputStream(Common::SeekableReadStream *inStream, bool dispose, uint startTime = 0, uint endTime = 0, uint numLoops = 1);
115 ~VorbisInputStream();
117 int readBuffer(int16 *buffer, const int numSamples);
119 bool endOfData() const { return _pos >= _bufferEnd; }
120 bool isStereo() const { return _isStereo; }
121 int getRate() const { return _rate; }
123 int32 getTotalPlayTime() const {
124 if (!_totalNumLoops)
125 return AudioStream::kUnknownPlayTime;
127 #ifdef USE_TREMOR
128 return (_endTime - _startTime) * _totalNumLoops;
129 #else
130 return (int32)((_endTime - _startTime) * 1000.0) * _totalNumLoops;
131 #endif
134 protected:
135 void refill();
138 VorbisInputStream::VorbisInputStream(Common::SeekableReadStream *inStream, bool dispose, uint startTime, uint endTime, uint numLoops) :
139 _inStream(inStream),
140 _disposeAfterUse(dispose),
141 _numLoops(numLoops),
142 _totalNumLoops(numLoops),
143 _bufferEnd(_buffer + ARRAYSIZE(_buffer)) {
145 bool err = (ov_open_callbacks(inStream, &_ovFile, NULL, 0, g_stream_wrap) < 0);
146 // FIXME: proper error handling!
147 assert(!err);
149 #ifdef USE_TREMOR
150 /* TODO: Symbian may have to use scumm_fixdfdi here? To quote:
151 "SumthinWicked says: fixing "relocation truncated to fit: ARM_26 __fixdfdi" during linking on GCC, see portdefs.h"
154 // In Tremor, the ov_time_seek() and ov_time_seek_page() calls take seeking
155 // positions in milliseconds as 64 bit integers, rather than in seconds as
156 // doubles as in Vorbisfile.
157 ogg_int64_t totalTime;
158 _startTime = startTime;
159 _endTime = endTime;
160 #else
161 double totalTime;
162 _startTime = startTime / 1000.0;
163 _endTime = endTime / 1000.0;
164 #endif
166 // If endTime was 0, or is past the end of the file, set it to the maximal time possible
167 totalTime = ov_time_total(&_ovFile, -1);
168 if (_endTime == 0 || _endTime > totalTime)
169 _endTime = totalTime;
171 // If the specified time range is empty, abort early.
172 if (_startTime >= _endTime) {
173 _pos = _bufferEnd;
174 return;
177 // Seek to the start position
178 ov_time_seek(&_ovFile, _startTime);
180 // Read in initial data
181 refill();
183 // Setup some header information
184 _isStereo = ov_info(&_ovFile, -1)->channels >= 2;
185 _rate = ov_info(&_ovFile, -1)->rate;
188 VorbisInputStream::~VorbisInputStream() {
189 ov_clear(&_ovFile);
190 if (_disposeAfterUse)
191 delete _inStream;
194 int VorbisInputStream::readBuffer(int16 *buffer, const int numSamples) {
195 int samples = 0;
196 while (samples < numSamples && _pos < _bufferEnd) {
197 const int len = MIN(numSamples - samples, (int)(_bufferEnd - _pos));
198 memcpy(buffer, _pos, len * 2);
199 buffer += len;
200 _pos += len;
201 samples += len;
202 if (_pos >= _bufferEnd) {
203 refill();
204 // If we are still out of data, and also past the end of specified
205 // time range, check whether looping is enabled...
206 if (_pos >= _bufferEnd && ov_time_tell(&_ovFile) >= _endTime) {
207 if (_numLoops != 1) {
208 // If looping is on and there are loops left, rewind to the start
209 if (_numLoops != 0)
210 _numLoops--;
211 ov_time_seek(&_ovFile, _startTime);
212 refill();
217 return samples;
220 void VorbisInputStream::refill() {
221 // Read the samples
222 uint len_left = sizeof(_buffer);
223 char *read_pos = (char *)_buffer;
225 while (len_left > 0) {
226 if (ov_time_tell(&_ovFile) >= _endTime) {
227 // If looping is on and there are loops left, rewind to the start
228 if (_numLoops == 1)
229 break; // Last loop, abort
230 if (_numLoops != 0)
231 _numLoops--;
232 ov_time_seek(&_ovFile, _startTime);
235 long result;
236 #ifdef USE_TREMOR
237 // Tremor ov_read() always returns data as signed 16 bit interleaved PCM
238 // in host byte order. As such, it does not take arguments to request
239 // specific signedness, byte order or bit depth as in Vorbisfile.
240 result = ov_read(&_ovFile, read_pos, len_left,
241 NULL);
242 #else
243 #ifdef SCUMM_BIG_ENDIAN
244 result = ov_read(&_ovFile, read_pos, len_left,
246 2, // 16 bit
247 1, // signed
248 NULL);
249 #else
250 result = ov_read(&_ovFile, read_pos, len_left,
252 2, // 16 bit
253 1, // signed
254 NULL);
255 #endif
256 #endif
257 if (result == OV_HOLE) {
258 // Possibly recoverable, just warn about it
259 warning("Corrupted data in Vorbis file");
260 } else if (result <= 0) {
261 if (result < 0)
262 debug(1, "Decode error %ld in Vorbis file", result);
263 // Don't delete it yet, that causes problems in
264 // the CD player emulation code.
265 memset(read_pos, 0, len_left);
266 break;
267 } else {
268 len_left -= result;
269 read_pos += result;
273 _pos = _buffer;
274 _bufferEnd = (int16 *)read_pos;
278 #pragma mark -
279 #pragma mark --- Ogg Vorbis factory functions ---
280 #pragma mark -
283 AudioStream *makeVorbisStream(
284 Common::SeekableReadStream *stream,
285 bool disposeAfterUse,
286 uint32 startTime,
287 uint32 duration,
288 uint numLoops) {
290 uint32 endTime = duration ? (startTime + duration) : 0;
292 return new VorbisInputStream(stream, disposeAfterUse, startTime, endTime, numLoops);
296 } // End of namespace Audio
298 #endif // #ifdef USE_VORBIS