#include "snd_ogg.h"
#include "snd_wav.h"
+#ifdef LINK_TO_LIBVORBIS
+#define OV_EXCLUDE_STATIC_CALLBACKS
+#include <ogg/ogg.h>
+#include <vorbis/vorbisfile.h>
+
+#define qov_clear ov_clear
+#define qov_info ov_info
+#define qov_comment ov_comment
+#define qov_open_callbacks ov_open_callbacks
+#define qov_pcm_seek ov_pcm_seek
+#define qov_pcm_total ov_pcm_total
+#define qov_read ov_read
+#define qvorbis_comment_query vorbis_comment_query
+
+qboolean OGG_OpenLibrary (void) {return true;}
+void OGG_CloseLibrary (void) {}
+#else
/*
=================================================================
static dllhandle_t vo_dll = NULL;
static dllhandle_t vf_dll = NULL;
-typedef struct
-{
- unsigned char *buffer;
- ogg_int64_t ind, buffsize;
-} ov_decode_t;
-
-
-static size_t ovcb_read (void *ptr, size_t size, size_t nb, void *datasource)
-{
- ov_decode_t *ov_decode = (ov_decode_t*)datasource;
- size_t remain, len;
-
- remain = ov_decode->buffsize - ov_decode->ind;
- len = size * nb;
- if (remain < len)
- len = remain - remain % size;
-
- memcpy (ptr, ov_decode->buffer + ov_decode->ind, len);
- ov_decode->ind += len;
-
- return len / size;
-}
-
-static int ovcb_seek (void *datasource, ogg_int64_t offset, int whence)
-{
- ov_decode_t *ov_decode = (ov_decode_t*)datasource;
-
- switch (whence)
- {
- case SEEK_SET:
- break;
- case SEEK_CUR:
- offset += ov_decode->ind;
- break;
- case SEEK_END:
- offset += ov_decode->buffsize;
- break;
- default:
- return -1;
- }
- if (offset < 0 || offset > ov_decode->buffsize)
- return -1;
-
- ov_decode->ind = offset;
- return 0;
-}
-
-static int ovcb_close (void *ov_decode)
-{
- return 0;
-}
-
-static long ovcb_tell (void *ov_decode)
-{
- return ((ov_decode_t*)ov_decode)->ind;
-}
-
/*
=================================================================
{
const char* dllnames_vo [] =
{
-#if defined(WIN64)
- "libvorbis64.dll",
-#elif defined(WIN32)
+#if defined(WIN32)
"libvorbis.dll",
"vorbis.dll",
#elif defined(MACOSX)
};
const char* dllnames_vf [] =
{
-#if defined(WIN64)
- "libvorbisfile64.dll",
-#elif defined(WIN32)
+#if defined(WIN32)
"libvorbisfile.dll",
"vorbisfile.dll",
#elif defined(MACOSX)
Sys_UnloadLibrary (&vo_dll);
}
+#endif
/*
=================================================================
=================================================================
*/
-#define STREAM_BUFFER_DURATION 1.5f // 1.5 sec
-#define STREAM_BUFFER_SIZE(format_ptr) ((int)(ceil (STREAM_BUFFER_DURATION * ((format_ptr)->speed * (format_ptr)->width * (format_ptr)->channels))))
+typedef struct
+{
+ unsigned char *buffer;
+ ogg_int64_t ind, buffsize;
+} ov_decode_t;
+
+static size_t ovcb_read (void *ptr, size_t size, size_t nb, void *datasource)
+{
+ ov_decode_t *ov_decode = (ov_decode_t*)datasource;
+ size_t remain, len;
+
+ remain = ov_decode->buffsize - ov_decode->ind;
+ len = size * nb;
+ if (remain < len)
+ len = remain - remain % size;
+
+ memcpy (ptr, ov_decode->buffer + ov_decode->ind, len);
+ ov_decode->ind += len;
+
+ return len / size;
+}
+
+static int ovcb_seek (void *datasource, ogg_int64_t offset, int whence)
+{
+ ov_decode_t *ov_decode = (ov_decode_t*)datasource;
+
+ switch (whence)
+ {
+ case SEEK_SET:
+ break;
+ case SEEK_CUR:
+ offset += ov_decode->ind;
+ break;
+ case SEEK_END:
+ offset += ov_decode->buffsize;
+ break;
+ default:
+ return -1;
+ }
+ if (offset < 0 || offset > ov_decode->buffsize)
+ return -1;
-// We work with 1 sec sequences, so this buffer must be able to contain
-// 1 sec of sound of the highest quality (48 KHz, 16 bit samples, stereo)
-static unsigned char resampling_buffer [48000 * 2 * 2];
+ ov_decode->ind = offset;
+ return 0;
+}
+static int ovcb_close (void *ov_decode)
+{
+ return 0;
+}
+
+static long ovcb_tell (void *ov_decode)
+{
+ return ((ov_decode_t*)ov_decode)->ind;
+}
// Per-sfx data structure
typedef struct
ogg_stream_perchannel_t* per_ch = (ogg_stream_perchannel_t *)*chfetcherpointer;
ogg_stream_persfx_t* per_sfx = (ogg_stream_persfx_t *)sfxfetcher;
snd_buffer_t* sb;
- int newlength, done, ret, bigendian;
+ int newlength, done, ret;
unsigned int real_start;
unsigned int factor;
}
sb->nbframes = 0;
- real_start = (float)ogg_start / per_sfx->format.speed * snd_renderbuffer->format.speed;
+ real_start = (unsigned int) ((float)ogg_start / per_sfx->format.speed * snd_renderbuffer->format.speed);
if (*start - real_start + nbsampleframes > sb->maxframes)
{
Con_Printf ("OGG_FetchSound: stream buffer too small after seek (%u sample frames required)\n",
per_ch->sb_offset = real_start;
- // We add exactly 1 sec of sound to the buffer:
- // 1- to ensure we won't lose any sample during the resampling process
- // 2- to force one call to OGG_FetchSound per second to regulate the workload
- if (sb->format.speed + sb->nbframes > sb->maxframes)
+ // We add more than one frame of sound to the buffer:
+ // 1- to ensure we won't lose many samples during the resampling process
+ // 2- to reduce calls to OGG_FetchSound to regulate workload
+ newlength = (int)(per_sfx->format.speed*STREAM_BUFFER_FILL);
+ if (newlength + sb->nbframes > sb->maxframes)
{
Con_Printf ("OGG_FetchSound: stream buffer overflow (%u sample frames / %u)\n",
sb->format.speed + sb->nbframes, sb->maxframes);
return NULL;
}
- newlength = per_sfx->format.speed * factor; // -> 1 sec of sound before resampling
+ newlength *= factor; // convert from sample frames to bytes
if(newlength > (int)sizeof(resampling_buffer))
newlength = sizeof(resampling_buffer);
// Decompress in the resampling_buffer
-#if BYTE_ORDER == BIG_ENDIAN
- bigendian = 1;
-#else
- bigendian = 0;
-#endif
done = 0;
- while ((ret = qov_read (&per_ch->vf, (char *)&resampling_buffer[done], (int)(newlength - done), bigendian, 2, 1, &per_ch->bs)) > 0)
+ while ((ret = qov_read (&per_ch->vf, (char *)&resampling_buffer[done], (int)(newlength - done), mem_bigendian, 2, 1, &per_ch->bs)) > 0)
done += ret;
Snd_AppendToSndBuffer (sb, resampling_buffer, (size_t)done / (size_t)factor, &per_sfx->format);
if(startcomment)
{
- *start = bound(0, atof(startcomment) * samplesfactor, numsamples);
+ *start = (unsigned int) bound(0, atof(startcomment) * samplesfactor, numsamples);
if(endcomment)
- *length = bound(0, atof(endcomment) * samplesfactor, numsamples);
+ *length = (unsigned int) bound(0, atof(endcomment) * samplesfactor, numsamples);
else if(lengthcomment)
- *length = bound(0, *start + atof(lengthcomment) * samplesfactor, numsamples);
+ *length = (unsigned int) bound(0, *start + atof(lengthcomment) * samplesfactor, numsamples);
}
}
ogg_int64_t len, buff_len;
double peak, gaindb;
+#ifndef LINK_TO_LIBVORBIS
if (!vf_dll)
return false;
+#endif
// Already loaded?
if (sfx->fetcher != NULL)
len = qov_pcm_total (&vf, -1) * vi->channels * 2; // 16 bits => "* 2"
// Decide if we go for a stream or a simple PCM cache
- buff_len = (int)ceil (STREAM_BUFFER_DURATION * (snd_renderbuffer->format.speed * 2 * vi->channels));
- if (snd_streaming.integer && len > (ogg_int64_t)filesize + 3 * buff_len)
+ buff_len = (int)ceil (STREAM_BUFFER_DURATION * snd_renderbuffer->format.speed) * 2 * vi->channels;
+ if (snd_streaming.integer && (len > (ogg_int64_t)filesize + 3 * buff_len || snd_streaming.integer >= 2))
{
ogg_stream_persfx_t* per_sfx;
{
char *buff;
ogg_int64_t done;
- int bs, bigendian;
+ int bs;
long ret;
snd_buffer_t *sb;
snd_format_t ogg_format;
buff = (char *)Mem_Alloc (snd_mempool, (int)len);
done = 0;
bs = 0;
-#if BYTE_ORDER == BIG_ENDIAN
- bigendian = 1;
-#else
- bigendian = 0;
-#endif
- while ((ret = qov_read (&vf, &buff[done], (int)(len - done), bigendian, 2, 1, &bs)) > 0)
+ while ((ret = qov_read (&vf, &buff[done], (int)(len - done), mem_bigendian, 2, 1, &bs)) > 0)
done += ret;
// Build the sound buffer
if(peak)
{
- sfx->volume_mult = min(1 / peak, exp(gaindb * 0.05 * log(10)));
+ sfx->volume_mult = min(1.0f / peak, exp(gaindb * 0.05f * log(10.0f)));
sfx->volume_peak = peak;
if (developer_loading.integer >= 2)
Con_Printf ("Ogg sound file \"%s\" uses ReplayGain (gain %f, peak %f)\n", filename, sfx->volume_mult, sfx->volume_peak);