1 /*
2 	Copyright (C) 2003-2005  Mathieu Olivier
3 
4 	This program is free software; you can redistribute it and/or
5 	modify it under the terms of the GNU General Public License
6 	as published by the Free Software Foundation; either version 2
7 	of the License, or (at your option) any later version.
8 
9 	This program is distributed in the hope that it will be useful,
10 	but WITHOUT ANY WARRANTY; without even the implied warranty of
11 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 	See the GNU General Public License for more details.
14 
15 	You should have received a copy of the GNU General Public License
16 	along with this program; if not, write to:
17 
18 		Free Software Foundation, Inc.
19 		59 Temple Place - Suite 330
20 		Boston, MA  02111-1307, USA
21 
22 */
23 
24 
25 #include "quakedef.h"
26 #include "snd_main.h"
27 #include "snd_ogg.h"
28 #include "snd_wav.h"
29 
30 #ifdef LINK_TO_LIBVORBIS
31 #define OV_EXCLUDE_STATIC_CALLBACKS
32 #include <ogg/ogg.h>
33 #include <vorbis/vorbisfile.h>
34 
35 #define qov_clear ov_clear
36 #define qov_info ov_info
37 #define qov_comment ov_comment
38 #define qov_open_callbacks ov_open_callbacks
39 #define qov_pcm_seek ov_pcm_seek
40 #define qov_pcm_total ov_pcm_total
41 #define qov_read ov_read
42 #define qvorbis_comment_query vorbis_comment_query
43 
OGG_OpenLibrary(void)44 qboolean OGG_OpenLibrary (void) {return true;}
OGG_CloseLibrary(void)45 void OGG_CloseLibrary (void) {}
46 #else
47 
48 /*
49 =================================================================
50 
51   Minimal set of definitions from the Ogg Vorbis lib
52   (C) COPYRIGHT 1994-2001 by the XIPHOPHORUS Company
53   http://www.xiph.org/
54 
55   WARNING: for a matter of simplicity, several pointer types are
56   casted to "void*", and most enumerated values are not included
57 
58 =================================================================
59 */
60 
61 #ifdef _MSC_VER
62 typedef __int64 ogg_int64_t;
63 #else
64 typedef long long ogg_int64_t;
65 #endif
66 
67 typedef struct
68 {
69 	size_t	(*read_func)	(void *ptr, size_t size, size_t nmemb, void *datasource);
70 	int		(*seek_func)	(void *datasource, ogg_int64_t offset, int whence);
71 	int		(*close_func)	(void *datasource);
72 	long	(*tell_func)	(void *datasource);
73 } ov_callbacks;
74 
75 typedef struct
76 {
77 	unsigned char	*data;
78 	int				storage;
79 	int				fill;
80 	int				returned;
81 	int				unsynced;
82 	int				headerbytes;
83 	int				bodybytes;
84 } ogg_sync_state;
85 
86 typedef struct
87 {
88 	int		version;
89 	int		channels;
90 	long	rate;
91 	long	bitrate_upper;
92 	long	bitrate_nominal;
93 	long	bitrate_lower;
94 	long	bitrate_window;
95 	void	*codec_setup;
96 } vorbis_info;
97 
98 typedef struct
99 {
100 	unsigned char	*body_data;
101 	long			body_storage;
102 	long			body_fill;
103 	long			body_returned;
104 	int				*lacing_vals;
105 	ogg_int64_t		*granule_vals;
106 	long			lacing_storage;
107 	long			lacing_fill;
108 	long			lacing_packet;
109 	long			lacing_returned;
110 	unsigned char	header[282];
111 	int				header_fill;
112 	int				e_o_s;
113 	int				b_o_s;
114 	long			serialno;
115 	long			pageno;
116 	ogg_int64_t		packetno;
117 	ogg_int64_t		granulepos;
118 } ogg_stream_state;
119 
120 typedef struct
121 {
122 	int			analysisp;
123 	vorbis_info	*vi;
124 	float		**pcm;
125 	float		**pcmret;
126 	int			pcm_storage;
127 	int			pcm_current;
128 	int			pcm_returned;
129 	int			preextrapolate;
130 	int			eofflag;
131 	long		lW;
132 	long		W;
133 	long		nW;
134 	long		centerW;
135 	ogg_int64_t	granulepos;
136 	ogg_int64_t	sequence;
137 	ogg_int64_t	glue_bits;
138 	ogg_int64_t	time_bits;
139 	ogg_int64_t	floor_bits;
140 	ogg_int64_t	res_bits;
141 	void		*backend_state;
142 } vorbis_dsp_state;
143 
144 typedef struct
145 {
146 	long			endbyte;
147 	int				endbit;
148 	unsigned char	*buffer;
149 	unsigned char	*ptr;
150 	long			storage;
151 } oggpack_buffer;
152 
153 typedef struct
154 {
155 	float				**pcm;
156 	oggpack_buffer		opb;
157 	long				lW;
158 	long				W;
159 	long				nW;
160 	int					pcmend;
161 	int					mode;
162 	int					eofflag;
163 	ogg_int64_t			granulepos;
164 	ogg_int64_t			sequence;
165 	vorbis_dsp_state	*vd;
166 	void				*localstore;
167 	long				localtop;
168 	long				localalloc;
169 	long				totaluse;
170 	void				*reap;  // VOIDED POINTER
171 	long				glue_bits;
172 	long				time_bits;
173 	long				floor_bits;
174 	long				res_bits;
175 	void				*internal;
176 } vorbis_block;
177 
178 typedef struct
179 {
180 	char **user_comments;
181 	int   *comment_lengths;
182 	int    comments;
183 	char  *vendor;
184 } vorbis_comment;
185 
186 typedef struct
187 {
188 	void				*datasource;
189 	int					seekable;
190 	ogg_int64_t			offset;
191 	ogg_int64_t			end;
192 	ogg_sync_state		oy;
193 	int					links;
194 	ogg_int64_t			*offsets;
195 	ogg_int64_t			*dataoffsets;
196 	long				*serialnos;
197 	ogg_int64_t			*pcmlengths;
198 	vorbis_info			*vi;
199 	vorbis_comment		*vc;
200 	ogg_int64_t			pcm_offset;
201 	int					ready_state;
202 	long				current_serialno;
203 	int					current_link;
204 	double				bittrack;
205 	double				samptrack;
206 	ogg_stream_state	os;
207 	vorbis_dsp_state	vd;
208 	vorbis_block		vb;
209 	ov_callbacks		callbacks;
210 } OggVorbis_File;
211 
212 
213 /*
214 =================================================================
215 
216   DarkPlaces definitions
217 
218 =================================================================
219 */
220 
221 // Functions exported from the vorbisfile library
222 static int (*qov_clear) (OggVorbis_File *vf);
223 static vorbis_info* (*qov_info) (OggVorbis_File *vf,int link);
224 static vorbis_comment* (*qov_comment) (OggVorbis_File *vf,int link);
225 static char * (*qvorbis_comment_query) (vorbis_comment *vc, const char *tag, int count);
226 static int (*qov_open_callbacks) (void *datasource, OggVorbis_File *vf,
227 								  char *initial, long ibytes,
228 								  ov_callbacks callbacks);
229 static int (*qov_pcm_seek) (OggVorbis_File *vf,ogg_int64_t pos);
230 static ogg_int64_t (*qov_pcm_total) (OggVorbis_File *vf,int i);
231 static long (*qov_read) (OggVorbis_File *vf,char *buffer,int length,
232 						 int bigendianp,int word,int sgned,int *bitstream);
233 
234 static dllfunction_t vorbisfilefuncs[] =
235 {
236 	{"ov_clear",				(void **) &qov_clear},
237 	{"ov_info",					(void **) &qov_info},
238 	{"ov_comment",				(void **) &qov_comment},
239 	{"ov_open_callbacks",		(void **) &qov_open_callbacks},
240 	{"ov_pcm_seek",				(void **) &qov_pcm_seek},
241 	{"ov_pcm_total",			(void **) &qov_pcm_total},
242 	{"ov_read",					(void **) &qov_read},
243 	{NULL, NULL}
244 };
245 
246 static dllfunction_t vorbisfuncs[] =
247 {
248 	{"vorbis_comment_query",	(void **) &qvorbis_comment_query},
249 	{NULL, NULL}
250 };
251 
252 // Handles for the Vorbis and Vorbisfile DLLs
253 static dllhandle_t vo_dll = NULL;
254 static dllhandle_t vf_dll = NULL;
255 
256 
257 /*
258 =================================================================
259 
260   DLL load & unload
261 
262 =================================================================
263 */
264 
265 /*
266 ====================
267 OGG_OpenLibrary
268 
269 Try to load the VorbisFile DLL
270 ====================
271 */
OGG_OpenLibrary(void)272 qboolean OGG_OpenLibrary (void)
273 {
274 	const char* dllnames_vo [] =
275 	{
276 #if defined(WIN32)
277 		"libvorbis-0.dll",
278 		"libvorbis.dll",
279 		"vorbis.dll",
280 #elif defined(MACOSX)
281 		"libvorbis.dylib",
282 #else
283 		"libvorbis.so.0",
284 		"libvorbis.so",
285 #endif
286 		NULL
287 	};
288 	const char* dllnames_vf [] =
289 	{
290 #if defined(WIN32)
291 		"libvorbisfile-3.dll",
292 		"libvorbisfile.dll",
293 		"vorbisfile.dll",
294 #elif defined(MACOSX)
295 		"libvorbisfile.dylib",
296 #else
297 		"libvorbisfile.so.3",
298 		"libvorbisfile.so",
299 #endif
300 		NULL
301 	};
302 
303 	// Already loaded?
304 	if (vf_dll)
305 		return true;
306 
307 // COMMANDLINEOPTION: Sound: -novorbis disables ogg vorbis sound support
308 	if (COM_CheckParm("-novorbis"))
309 		return false;
310 
311 	// Load the DLLs
312 	// We need to load both by hand because some OSes seem to not load
313 	// the vorbis DLL automatically when loading the VorbisFile DLL
314 	return Sys_LoadLibrary (dllnames_vo, &vo_dll, vorbisfuncs) && Sys_LoadLibrary (dllnames_vf, &vf_dll, vorbisfilefuncs);
315 }
316 
317 
318 /*
319 ====================
320 OGG_CloseLibrary
321 
322 Unload the VorbisFile DLL
323 ====================
324 */
OGG_CloseLibrary(void)325 void OGG_CloseLibrary (void)
326 {
327 	Sys_UnloadLibrary (&vf_dll);
328 	Sys_UnloadLibrary (&vo_dll);
329 }
330 
331 #endif
332 
333 /*
334 =================================================================
335 
336 	Ogg Vorbis decoding
337 
338 =================================================================
339 */
340 
341 typedef struct
342 {
343 	unsigned char *buffer;
344 	ogg_int64_t ind, buffsize;
345 } ov_decode_t;
346 
ovcb_read(void * ptr,size_t size,size_t nb,void * datasource)347 static size_t ovcb_read (void *ptr, size_t size, size_t nb, void *datasource)
348 {
349 	ov_decode_t *ov_decode = (ov_decode_t*)datasource;
350 	size_t remain, len;
351 
352 	remain = ov_decode->buffsize - ov_decode->ind;
353 	len = size * nb;
354 	if (remain < len)
355 		len = remain - remain % size;
356 
357 	memcpy (ptr, ov_decode->buffer + ov_decode->ind, len);
358 	ov_decode->ind += len;
359 
360 	return len / size;
361 }
362 
ovcb_seek(void * datasource,ogg_int64_t offset,int whence)363 static int ovcb_seek (void *datasource, ogg_int64_t offset, int whence)
364 {
365 	ov_decode_t *ov_decode = (ov_decode_t*)datasource;
366 
367 	switch (whence)
368 	{
369 		case SEEK_SET:
370 			break;
371 		case SEEK_CUR:
372 			offset += ov_decode->ind;
373 			break;
374 		case SEEK_END:
375 			offset += ov_decode->buffsize;
376 			break;
377 		default:
378 			return -1;
379 	}
380 	if (offset < 0 || offset > ov_decode->buffsize)
381 		return -1;
382 
383 	ov_decode->ind = offset;
384 	return 0;
385 }
386 
ovcb_close(void * ov_decode)387 static int ovcb_close (void *ov_decode)
388 {
389 	return 0;
390 }
391 
ovcb_tell(void * ov_decode)392 static long ovcb_tell (void *ov_decode)
393 {
394 	return ((ov_decode_t*)ov_decode)->ind;
395 }
396 
397 // Per-sfx data structure
398 typedef struct
399 {
400 	unsigned char	*file;
401 	size_t			filesize;
402 } ogg_stream_persfx_t;
403 
404 // Per-channel data structure
405 typedef struct
406 {
407 	OggVorbis_File	vf;
408 	ov_decode_t		ov_decode;
409 	int				bs;
410 	int				buffer_firstframe;
411 	int				buffer_numframes;
412 	unsigned char	buffer[STREAM_BUFFERSIZE*4];
413 } ogg_stream_perchannel_t;
414 
415 
416 static const ov_callbacks callbacks = {ovcb_read, ovcb_seek, ovcb_close, ovcb_tell};
417 
418 /*
419 ====================
420 OGG_GetSamplesFloat
421 ====================
422 */
OGG_GetSamplesFloat(channel_t * ch,sfx_t * sfx,int firstsampleframe,int numsampleframes,float * outsamplesfloat)423 static void OGG_GetSamplesFloat (channel_t *ch, sfx_t *sfx, int firstsampleframe, int numsampleframes, float *outsamplesfloat)
424 {
425 	ogg_stream_perchannel_t *per_ch = (ogg_stream_perchannel_t *)ch->fetcher_data;
426 	ogg_stream_persfx_t *per_sfx = (ogg_stream_persfx_t *)sfx->fetcher_data;
427 	int f = sfx->format.width * sfx->format.channels; // bytes per frame in the buffer
428 	short *buf;
429 	int i, len;
430 	int newlength, done, ret;
431 
432 	// if this channel does not yet have a channel fetcher, make one
433 	if (per_ch == NULL)
434 	{
435 		// allocate a struct to keep track of our file position and buffer
436 		per_ch = (ogg_stream_perchannel_t *)Mem_Alloc(snd_mempool, sizeof(*per_ch));
437 		// begin decoding the file
438 		per_ch->ov_decode.buffer = per_sfx->file;
439 		per_ch->ov_decode.ind = 0;
440 		per_ch->ov_decode.buffsize = per_sfx->filesize;
441 		if (qov_open_callbacks(&per_ch->ov_decode, &per_ch->vf, NULL, 0, callbacks) < 0)
442 		{
443 			// this never happens - this function succeeded earlier on the same data
444 			Mem_Free(per_ch);
445 			return;
446 		}
447 		per_ch->bs = 0;
448 		per_ch->buffer_firstframe = 0;
449 		per_ch->buffer_numframes = 0;
450 		// attach the struct to our channel
451 		ch->fetcher_data = (void *)per_ch;
452 	}
453 
454 	// if the request is too large for our buffer, loop...
455 	while (numsampleframes * f > (int)sizeof(per_ch->buffer))
456 	{
457 		done = sizeof(per_ch->buffer) / f;
458 		OGG_GetSamplesFloat(ch, sfx, firstsampleframe, done, outsamplesfloat);
459 		firstsampleframe += done;
460 		numsampleframes -= done;
461 		outsamplesfloat += done * sfx->format.channels;
462 	}
463 
464 	// seek if the request is before the current buffer (loop back)
465 	// seek if the request starts beyond the current buffer by at least one frame (channel was zero volume for a while)
466 	// do not seek if the request overlaps the buffer end at all (expected behavior)
467 	if (per_ch->buffer_firstframe > firstsampleframe || per_ch->buffer_firstframe + per_ch->buffer_numframes < firstsampleframe)
468 	{
469 		// we expect to decode forward from here so this will be our new buffer start
470 		per_ch->buffer_firstframe = firstsampleframe;
471 		per_ch->buffer_numframes = 0;
472 		ret = qov_pcm_seek(&per_ch->vf, (ogg_int64_t)firstsampleframe);
473 		if (ret != 0)
474 		{
475 			// LordHavoc: we can't Con_Printf here, not thread safe...
476 			//Con_Printf("OGG_FetchSound: qov_pcm_seek(..., %d) returned %d\n", firstsampleframe, ret);
477 			return;
478 		}
479 	}
480 
481 	// decompress the file as needed
482 	if (firstsampleframe + numsampleframes > per_ch->buffer_firstframe + per_ch->buffer_numframes)
483 	{
484 		// first slide the buffer back, discarding any data preceding the range we care about
485 		int offset = firstsampleframe - per_ch->buffer_firstframe;
486 		int keeplength = per_ch->buffer_numframes - offset;
487 		if (keeplength > 0)
488 			memmove(per_ch->buffer, per_ch->buffer + offset * sfx->format.width * sfx->format.channels, keeplength * sfx->format.width * sfx->format.channels);
489 		per_ch->buffer_firstframe = firstsampleframe;
490 		per_ch->buffer_numframes -= offset;
491 		// decompress as much as we can fit in the buffer
492 		newlength = sizeof(per_ch->buffer) - per_ch->buffer_numframes * f;
493 		done = 0;
494 		while (newlength > done && (ret = qov_read(&per_ch->vf, (char *)per_ch->buffer + per_ch->buffer_numframes * f + done, (int)(newlength - done), mem_bigendian, 2, 1, &per_ch->bs)) > 0)
495 			done += ret;
496 		// clear the missing space if any
497 		if (done < newlength)
498 			memset(per_ch->buffer + done, 0, newlength - done);
499 		// we now have more data in the buffer
500 		per_ch->buffer_numframes += done / f;
501 	}
502 
503 	// convert the sample format for the caller
504 	buf = (short *)((char *)per_ch->buffer + (firstsampleframe - per_ch->buffer_firstframe) * f);
505 	len = numsampleframes * sfx->format.channels;
506 	for (i = 0;i < len;i++)
507 		outsamplesfloat[i] = buf[i] * (1.0f / 32768.0f);
508 }
509 
510 
511 /*
512 ====================
513 OGG_StopChannel
514 ====================
515 */
OGG_StopChannel(channel_t * ch)516 static void OGG_StopChannel(channel_t *ch)
517 {
518 	ogg_stream_perchannel_t *per_ch = (ogg_stream_perchannel_t *)ch->fetcher_data;
519 	if (per_ch != NULL)
520 	{
521 		// release the vorbis decompressor
522 		qov_clear(&per_ch->vf);
523 		Mem_Free(per_ch);
524 	}
525 }
526 
527 
528 /*
529 ====================
530 OGG_FreeSfx
531 ====================
532 */
OGG_FreeSfx(sfx_t * sfx)533 static void OGG_FreeSfx(sfx_t *sfx)
534 {
535 	ogg_stream_persfx_t *per_sfx = (ogg_stream_persfx_t *)sfx->fetcher_data;
536 	// free the complete file we were keeping around
537 	Mem_Free(per_sfx->file);
538 	// free the file information structure
539 	Mem_Free(per_sfx);
540 }
541 
542 
543 static const snd_fetcher_t ogg_fetcher = {OGG_GetSamplesFloat, OGG_StopChannel, OGG_FreeSfx};
544 
OGG_DecodeTags(vorbis_comment * vc,unsigned int * start,unsigned int * length,unsigned int numsamples,double * peak,double * gaindb)545 static void OGG_DecodeTags(vorbis_comment *vc, unsigned int *start, unsigned int *length, unsigned int numsamples, double *peak, double *gaindb)
546 {
547 	const char *startcomment = NULL, *lengthcomment = NULL, *endcomment = NULL, *thiscomment = NULL;
548 
549 	*start = numsamples;
550 	*length = numsamples;
551 	*peak = 0.0;
552 	*gaindb = 0.0;
553 
554 	if(!vc)
555 		return;
556 
557 	thiscomment = qvorbis_comment_query(vc, "REPLAYGAIN_TRACK_PEAK", 0);
558 	if(thiscomment)
559 		*peak = atof(thiscomment);
560 	thiscomment = qvorbis_comment_query(vc, "REPLAYGAIN_TRACK_GAIN", 0);
561 	if(thiscomment)
562 		*gaindb = atof(thiscomment);
563 
564 	startcomment = qvorbis_comment_query(vc, "LOOP_START", 0); // DarkPlaces, and some Japanese app
565 	if(startcomment)
566 	{
567 		endcomment = qvorbis_comment_query(vc, "LOOP_END", 0);
568 		if(!endcomment)
569 			lengthcomment = qvorbis_comment_query(vc, "LOOP_LENGTH", 0);
570 	}
571 	else
572 	{
573 		startcomment = qvorbis_comment_query(vc, "LOOPSTART", 0); // RPG Maker VX
574 		if(startcomment)
575 		{
576 			lengthcomment = qvorbis_comment_query(vc, "LOOPLENGTH", 0);
577 			if(!lengthcomment)
578 				endcomment = qvorbis_comment_query(vc, "LOOPEND", 0);
579 		}
580 		else
581 		{
582 			startcomment = qvorbis_comment_query(vc, "LOOPPOINT", 0); // Sonic Robo Blast 2
583 		}
584 	}
585 
586 	if(startcomment)
587 	{
588 		*start = (unsigned int) bound(0, atof(startcomment), numsamples);
589 		if(endcomment)
590 			*length = (unsigned int) bound(0, atof(endcomment), numsamples);
591 		else if(lengthcomment)
592 			*length = (unsigned int) bound(0, *start + atof(lengthcomment), numsamples);
593 	}
594 }
595 
596 /*
597 ====================
598 OGG_LoadVorbisFile
599 
600 Load an Ogg Vorbis file into memory
601 ====================
602 */
OGG_LoadVorbisFile(const char * filename,sfx_t * sfx)603 qboolean OGG_LoadVorbisFile(const char *filename, sfx_t *sfx)
604 {
605 	unsigned char *data;
606 	fs_offset_t filesize;
607 	ov_decode_t ov_decode;
608 	OggVorbis_File vf;
609 	vorbis_info *vi;
610 	vorbis_comment *vc;
611 	double peak, gaindb;
612 
613 #ifndef LINK_TO_LIBVORBIS
614 	if (!vf_dll)
615 		return false;
616 #endif
617 
618 	// Return if already loaded
619 	if (sfx->fetcher != NULL)
620 		return true;
621 
622 	// Load the file completely
623 	data = FS_LoadFile(filename, snd_mempool, false, &filesize);
624 	if (data == NULL)
625 		return false;
626 
627 	if (developer_loading.integer >= 2)
628 		Con_Printf("Loading Ogg Vorbis file \"%s\"\n", filename);
629 
630 	// Open it with the VorbisFile API
631 	ov_decode.buffer = data;
632 	ov_decode.ind = 0;
633 	ov_decode.buffsize = filesize;
634 	if (qov_open_callbacks(&ov_decode, &vf, NULL, 0, callbacks) < 0)
635 	{
636 		Con_Printf("error while opening Ogg Vorbis file \"%s\"\n", filename);
637 		Mem_Free(data);
638 		return false;
639 	}
640 
641 	// Get the stream information
642 	vi = qov_info(&vf, -1);
643 	if (vi->channels < 1 || vi->channels > 2)
644 	{
645 		Con_Printf("%s has an unsupported number of channels (%i)\n",
646 					sfx->name, vi->channels);
647 		qov_clear (&vf);
648 		Mem_Free(data);
649 		return false;
650 	}
651 
652 	sfx->format.speed = vi->rate;
653 	sfx->format.channels = vi->channels;
654 	sfx->format.width = 2;  // We always work with 16 bits samples
655 
656 	sfx->total_length = qov_pcm_total(&vf, -1);
657 
658 	if (snd_streaming.integer && (snd_streaming.integer >= 2 || sfx->total_length > max(sizeof(ogg_stream_perchannel_t), snd_streaming_length.value * sfx->format.speed)))
659 	{
660 		// large sounds use the OGG fetcher to decode the file on demand (but the entire file is held in memory)
661 		ogg_stream_persfx_t* per_sfx;
662 		if (developer_loading.integer >= 2)
663 			Con_Printf("Ogg sound file \"%s\" will be streamed\n", filename);
664 		per_sfx = (ogg_stream_persfx_t *)Mem_Alloc(snd_mempool, sizeof(*per_sfx));
665 		sfx->memsize += sizeof (*per_sfx);
666 		per_sfx->file = data;
667 		per_sfx->filesize = filesize;
668 		sfx->memsize += filesize;
669 		sfx->fetcher_data = per_sfx;
670 		sfx->fetcher = &ogg_fetcher;
671 		sfx->flags |= SFXFLAG_STREAMED;
672 		vc = qov_comment(&vf, -1);
673 		OGG_DecodeTags(vc, &sfx->loopstart, &sfx->total_length, sfx->total_length, &peak, &gaindb);
674 		qov_clear(&vf);
675 	}
676 	else
677 	{
678 		// small sounds are entirely loaded and use the PCM fetcher
679 		char *buff;
680 		ogg_int64_t len;
681 		ogg_int64_t done;
682 		int bs;
683 		long ret;
684 		if (developer_loading.integer >= 2)
685 			Con_Printf ("Ogg sound file \"%s\" will be cached\n", filename);
686 		len = sfx->total_length * sfx->format.channels * sfx->format.width;
687 		sfx->flags &= ~SFXFLAG_STREAMED;
688 		sfx->memsize += len;
689 		sfx->fetcher = &wav_fetcher;
690 		sfx->fetcher_data = Mem_Alloc(snd_mempool, (size_t)len);
691 		buff = (char *)sfx->fetcher_data;
692 		done = 0;
693 		bs = 0;
694 		while ((ret = qov_read(&vf, &buff[done], (int)(len - done), mem_bigendian, 2, 1, &bs)) > 0)
695 			done += ret;
696 		vc = qov_comment(&vf, -1);
697 		OGG_DecodeTags(vc, &sfx->loopstart, &sfx->total_length, sfx->total_length, &peak, &gaindb);
698 		qov_clear(&vf);
699 		Mem_Free(data);
700 	}
701 
702 	if(peak)
703 	{
704 		sfx->volume_mult = min(1.0f / peak, exp(gaindb * 0.05f * log(10.0f)));
705 		sfx->volume_peak = peak;
706 		if (developer_loading.integer >= 2)
707 			Con_Printf ("Ogg sound file \"%s\" uses ReplayGain (gain %f, peak %f)\n", filename, sfx->volume_mult, sfx->volume_peak);
708 	}
709 	else if(gaindb != 0)
710 	{
711 		sfx->volume_mult = min(1.0f / peak, exp(gaindb * 0.05f * log(10.0f)));
712 		sfx->volume_peak = 1.0; // if peak is not defined, we won't trust it
713 		if (developer_loading.integer >= 2)
714 			Con_Printf ("Ogg sound file \"%s\" uses ReplayGain (gain %f, peak not defined and assumed to be %f)\n", filename, sfx->volume_mult, sfx->volume_peak);
715 	}
716 
717 	return true;
718 }
719