1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
5 Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de>
6 
7 This file is part of Quake III Arena source code.
8 
9 Quake III Arena source code is free software; you can redistribute it
10 and/or modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the License,
12 or (at your option) any later version.
13 
14 Quake III Arena source code is distributed in the hope that it will be
15 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Quake III Arena source code; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22 ===========================================================================
23 */
24 
25 // OGG support is enabled by this define
26 #ifdef USE_CODEC_VORBIS
27 
28 // includes for the Q3 sound system
29 #include "client.h"
30 #include "snd_codec.h"
31 
32 // includes for the OGG codec
33 #include <errno.h>
34 #define OV_EXCLUDE_STATIC_CALLBACKS
35 #include <vorbis/vorbisfile.h>
36 
37 // The OGG codec can return the samples in a number of different formats,
38 // we use the standard signed short format.
39 #define OGG_SAMPLEWIDTH 2
40 
41 // Q3 OGG codec
42 snd_codec_t ogg_codec =
43 {
44 	".ogg",
45 	S_OGG_CodecLoad,
46 	S_OGG_CodecOpenStream,
47 	S_OGG_CodecReadStream,
48 	S_OGG_CodecCloseStream,
49 	NULL
50 };
51 
52 // callbacks for vobisfile
53 
54 // fread() replacement
S_OGG_Callback_read(void * ptr,size_t size,size_t nmemb,void * datasource)55 size_t S_OGG_Callback_read(void *ptr, size_t size, size_t nmemb, void *datasource)
56 {
57 	snd_stream_t *stream;
58 	int byteSize = 0;
59 	int bytesRead = 0;
60 	size_t nMembRead = 0;
61 
62 	// check if input is valid
63 	if(!ptr)
64 	{
65 		errno = EFAULT;
66 		return 0;
67 	}
68 
69 	if(!(size && nmemb))
70 	{
71 		// It's not an error, caller just wants zero bytes!
72 		errno = 0;
73 		return 0;
74 	}
75 
76 	if(!datasource)
77 	{
78 		errno = EBADF;
79 		return 0;
80 	}
81 
82 	// we use a snd_stream_t in the generic pointer to pass around
83 	stream = (snd_stream_t *) datasource;
84 
85 	// FS_Read does not support multi-byte elements
86 	byteSize = nmemb * size;
87 
88 	// read it with the Q3 function FS_Read()
89 	bytesRead = FS_Read(ptr, byteSize, stream->file);
90 
91 	// update the file position
92 	stream->pos += bytesRead;
93 
94 	// this function returns the number of elements read not the number of bytes
95 	nMembRead = bytesRead / size;
96 
97 	// even if the last member is only read partially
98 	// it is counted as a whole in the return value
99 	if(bytesRead % size)
100 	{
101 		nMembRead++;
102 	}
103 
104 	return nMembRead;
105 }
106 
107 // fseek() replacement
S_OGG_Callback_seek(void * datasource,ogg_int64_t offset,int whence)108 int S_OGG_Callback_seek(void *datasource, ogg_int64_t offset, int whence)
109 {
110 	snd_stream_t *stream;
111 	int retVal = 0;
112 
113 	// check if input is valid
114 	if(!datasource)
115 	{
116 		errno = EBADF;
117 		return -1;
118 	}
119 
120 	// snd_stream_t in the generic pointer
121 	stream = (snd_stream_t *) datasource;
122 
123 	// we must map the whence to its Q3 counterpart
124 	switch(whence)
125 	{
126 		case SEEK_SET :
127 		{
128 			// set the file position in the actual file with the Q3 function
129 			retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_SET);
130 
131 			// something has gone wrong, so we return here
132 			if(retVal < 0)
133 			{
134 			 return retVal;
135 			}
136 
137 			// keep track of file position
138 			stream->pos = (int) offset;
139 			break;
140 		}
141 
142 		case SEEK_CUR :
143 		{
144 			// set the file position in the actual file with the Q3 function
145 			retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_CUR);
146 
147 			// something has gone wrong, so we return here
148 			if(retVal < 0)
149 			{
150 			 return retVal;
151 			}
152 
153 			// keep track of file position
154 			stream->pos += (int) offset;
155 			break;
156 		}
157 
158 		case SEEK_END :
159 		{
160 			// Quake 3 seems to have trouble with FS_SEEK_END
161 			// so we use the file length and FS_SEEK_SET
162 
163 			// set the file position in the actual file with the Q3 function
164 			retVal = FS_Seek(stream->file, (long) stream->length + (long) offset, FS_SEEK_SET);
165 
166 			// something has gone wrong, so we return here
167 			if(retVal < 0)
168 			{
169 			 return retVal;
170 			}
171 
172 			// keep track of file position
173 			stream->pos = stream->length + (int) offset;
174 			break;
175 		}
176 
177 		default :
178 		{
179 			// unknown whence, so we return an error
180 			errno = EINVAL;
181 			return -1;
182 		}
183 	}
184 
185 	// stream->pos shouldn't be smaller than zero or bigger than the filesize
186 	stream->pos = (stream->pos < 0) ? 0 : stream->pos;
187 	stream->pos = (stream->pos > stream->length) ? stream->length : stream->pos;
188 
189 	return 0;
190 }
191 
192 // fclose() replacement
S_OGG_Callback_close(void * datasource)193 int S_OGG_Callback_close(void *datasource)
194 {
195 	// we do nothing here and close all things manually in S_OGG_CodecCloseStream()
196 	return 0;
197 }
198 
199 // ftell() replacement
S_OGG_Callback_tell(void * datasource)200 long S_OGG_Callback_tell(void *datasource)
201 {
202 	snd_stream_t   *stream;
203 
204 	// check if input is valid
205 	if(!datasource)
206 	{
207 		errno = EBADF;
208 		return -1;
209 	}
210 
211 	// snd_stream_t in the generic pointer
212 	stream = (snd_stream_t *) datasource;
213 
214 	return (long) FS_FTell(stream->file);
215 }
216 
217 // the callback structure
218 const ov_callbacks S_OGG_Callbacks =
219 {
220  &S_OGG_Callback_read,
221  &S_OGG_Callback_seek,
222  &S_OGG_Callback_close,
223  &S_OGG_Callback_tell
224 };
225 
226 /*
227 =================
228 S_OGG_CodecOpenStream
229 =================
230 */
S_OGG_CodecOpenStream(const char * filename)231 snd_stream_t *S_OGG_CodecOpenStream(const char *filename)
232 {
233 	snd_stream_t *stream;
234 
235 	// OGG codec control structure
236 	OggVorbis_File *vf;
237 
238 	// some variables used to get informations about the OGG
239 	vorbis_info *OGGInfo;
240 	ogg_int64_t numSamples;
241 
242 	// check if input is valid
243 	if(!filename)
244 	{
245 		return NULL;
246 	}
247 
248 	// Open the stream
249 	stream = S_CodecUtilOpen(filename, &ogg_codec);
250 	if(!stream)
251 	{
252 		return NULL;
253 	}
254 
255 	// alloctate the OggVorbis_File
256 	vf = Z_Malloc(sizeof(OggVorbis_File));
257 	if(!vf)
258 	{
259 		S_CodecUtilClose(&stream);
260 
261 		return NULL;
262 	}
263 
264 	// open the codec with our callbacks and stream as the generic pointer
265 	if(ov_open_callbacks(stream, vf, NULL, 0, S_OGG_Callbacks) != 0)
266 	{
267 		Z_Free(vf);
268 
269 		S_CodecUtilClose(&stream);
270 
271 		return NULL;
272 	}
273 
274 	// the stream must be seekable
275 	if(!ov_seekable(vf))
276 	{
277 		ov_clear(vf);
278 
279 		Z_Free(vf);
280 
281 		S_CodecUtilClose(&stream);
282 
283 		return NULL;
284 	}
285 
286 	// we only support OGGs with one substream
287 	if(ov_streams(vf) != 1)
288 	{
289 		ov_clear(vf);
290 
291 		Z_Free(vf);
292 
293 		S_CodecUtilClose(&stream);
294 
295 		return NULL;
296 	}
297 
298 	// get the info about channels and rate
299 	OGGInfo = ov_info(vf, 0);
300 	if(!OGGInfo)
301 	{
302 		ov_clear(vf);
303 
304 		Z_Free(vf);
305 
306 		S_CodecUtilClose(&stream);
307 
308 		return NULL;
309 	}
310 
311 	// get the number of sample-frames in the OGG
312 	numSamples = ov_pcm_total(vf, 0);
313 
314 	// fill in the info-structure in the stream
315 	stream->info.rate = OGGInfo->rate;
316 	stream->info.width = OGG_SAMPLEWIDTH;
317 	stream->info.channels = OGGInfo->channels;
318 	stream->info.samples = numSamples;
319 	stream->info.size = stream->info.samples * stream->info.channels * stream->info.width;
320 	stream->info.dataofs = 0;
321 
322 	// We use stream->pos for the file pointer in the compressed ogg file
323 	stream->pos = 0;
324 
325 	// We use the generic pointer in stream for the OGG codec control structure
326 	stream->ptr = vf;
327 
328 	return stream;
329 }
330 
331 /*
332 =================
333 S_OGG_CodecCloseStream
334 =================
335 */
S_OGG_CodecCloseStream(snd_stream_t * stream)336 void S_OGG_CodecCloseStream(snd_stream_t *stream)
337 {
338 	// check if input is valid
339 	if(!stream)
340 	{
341 		return;
342 	}
343 
344 	// let the OGG codec cleanup its stuff
345 	ov_clear((OggVorbis_File *) stream->ptr);
346 
347 	// free the OGG codec control struct
348 	Z_Free(stream->ptr);
349 
350 	// close the stream
351 	S_CodecUtilClose(&stream);
352 }
353 
354 /*
355 =================
356 S_OGG_CodecReadStream
357 =================
358 */
S_OGG_CodecReadStream(snd_stream_t * stream,int bytes,void * buffer)359 int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
360 {
361 	// buffer handling
362 	int bytesRead, bytesLeft, c;
363 	char *bufPtr;
364 
365 	// Bitstream for the decoder
366 	int BS = 0;
367 
368 	// big endian machines want their samples in big endian order
369 	int IsBigEndian = 0;
370 
371 #	ifdef Q3_BIG_ENDIAN
372 	IsBigEndian = 1;
373 #	endif // Q3_BIG_ENDIAN
374 
375 	// check if input is valid
376 	if(!(stream && buffer))
377 	{
378 		return 0;
379 	}
380 
381 	if(bytes <= 0)
382 	{
383 		return 0;
384 	}
385 
386 	bytesRead = 0;
387 	bytesLeft = bytes;
388 	bufPtr = buffer;
389 
390 	// cycle until we have the requested or all available bytes read
391 	while(-1)
392 	{
393 		// read some bytes from the OGG codec
394 		c = ov_read((OggVorbis_File *) stream->ptr, bufPtr, bytesLeft, IsBigEndian, OGG_SAMPLEWIDTH, 1, &BS);
395 
396 		// no more bytes are left
397 		if(c <= 0)
398 		{
399 			break;
400 		}
401 
402 		bytesRead += c;
403 		bytesLeft -= c;
404 		bufPtr += c;
405 
406 		// we have enough bytes
407 		if(bytesLeft <= 0)
408 		{
409 			break;
410 		}
411 	}
412 
413 	return bytesRead;
414 }
415 
416 /*
417 =====================================================================
418 S_OGG_CodecLoad
419 
420 We handle S_OGG_CodecLoad as a special case of the streaming functions
421 where we read the whole stream at once.
422 ======================================================================
423 */
S_OGG_CodecLoad(const char * filename,snd_info_t * info)424 void *S_OGG_CodecLoad(const char *filename, snd_info_t *info)
425 {
426 	snd_stream_t *stream;
427 	byte *buffer;
428 	int bytesRead;
429 
430 	// check if input is valid
431 	if(!(filename && info))
432 	{
433 		return NULL;
434 	}
435 
436 	// open the file as a stream
437 	stream = S_OGG_CodecOpenStream(filename);
438 	if(!stream)
439 	{
440 		return NULL;
441 	}
442 
443 	// copy over the info
444 	info->rate = stream->info.rate;
445 	info->width = stream->info.width;
446 	info->channels = stream->info.channels;
447 	info->samples = stream->info.samples;
448 	info->size = stream->info.size;
449 	info->dataofs = stream->info.dataofs;
450 
451 	// allocate a buffer
452 	// this buffer must be free-ed by the caller of this function
453     	buffer = Z_Malloc(info->size);
454 	if(!buffer)
455 	{
456 		S_OGG_CodecCloseStream(stream);
457 
458 		return NULL;
459 	}
460 
461 	// fill the buffer
462 	bytesRead = S_OGG_CodecReadStream(stream, info->size, buffer);
463 
464 	// we don't even have read a single byte
465 	if(bytesRead <= 0)
466 	{
467 		Z_Free(buffer);
468 		S_OGG_CodecCloseStream(stream);
469 
470 		return NULL;
471 	}
472 
473 	S_OGG_CodecCloseStream(stream);
474 
475 	return buffer;
476 }
477 
478 #endif // USE_CODEC_VORBIS
479