X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=snd_ogg.c;h=0ee16bab4bd7f70cfd64d7310b6b9ba8f72001d9;hb=ab79f78df3d2083426b0836a85993df69fd483b3;hp=a5dba1da6d97fe90178b10ca8d99c20cc86b8045;hpb=7ec974a923006e2886b1d5397e4e54ece0281173;p=xonotic%2Fdarkplaces.git diff --git a/snd_ogg.c b/snd_ogg.c index a5dba1da..0ee16bab 100644 --- a/snd_ogg.c +++ b/snd_ogg.c @@ -25,7 +25,25 @@ #include "quakedef.h" #include "snd_main.h" #include "snd_ogg.h" - +#include "snd_wav.h" + +#ifdef LINK_TO_LIBVORBIS +#define OV_EXCLUDE_STATIC_CALLBACKS +#include +#include + +#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 /* ================================================================= @@ -204,7 +222,7 @@ typedef struct static int (*qov_clear) (OggVorbis_File *vf); static vorbis_info* (*qov_info) (OggVorbis_File *vf,int link); static vorbis_comment* (*qov_comment) (OggVorbis_File *vf,int link); -static char * (*qvorbis_comment_query) (vorbis_comment *vc, char *tag, int count); +static char * (*qvorbis_comment_query) (vorbis_comment *vc, const char *tag, int count); static int (*qov_open_callbacks) (void *datasource, OggVorbis_File *vf, char *initial, long ibytes, ov_callbacks callbacks); @@ -235,63 +253,6 @@ static dllfunction_t vorbisfuncs[] = 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; -} - /* ================================================================= @@ -313,6 +274,7 @@ qboolean OGG_OpenLibrary (void) const char* dllnames_vo [] = { #if defined(WIN32) + "libvorbis-0.dll", "libvorbis.dll", "vorbis.dll", #elif defined(MACOSX) @@ -326,6 +288,7 @@ qboolean OGG_OpenLibrary (void) const char* dllnames_vf [] = { #if defined(WIN32) + "libvorbisfile-3.dll", "libvorbisfile.dll", "vorbisfile.dll", #elif defined(MACOSX) @@ -365,6 +328,7 @@ void OGG_CloseLibrary (void) Sys_UnloadLibrary (&vo_dll); } +#endif /* ================================================================= @@ -374,6 +338,62 @@ void OGG_CloseLibrary (void) ================================================================= */ +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; +} + // Per-sfx data structure typedef struct { @@ -514,10 +534,11 @@ static const snd_buffer_t* OGG_FetchSound (void *sfxfetcher, void **chfetcherpoi // 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) + // this is how much we FETCH... + if ((size_t) ((double) newlength * (double)sb->format.speed / (double)per_sfx->format.speed) + sb->nbframes > sb->maxframes) { - Con_Printf ("OGG_FetchSound: stream buffer overflow (%u sample frames / %u)\n", - sb->format.speed + sb->nbframes, sb->maxframes); + Con_Printf ("OGG_FetchSound: stream buffer overflow (%u + %u = %u sample frames / %u)\n", + (unsigned int) ((double) newlength * (double)sb->format.speed / (double)per_sfx->format.speed), sb->nbframes, (unsigned int) ((double) newlength * (double)sb->format.speed / (double)per_sfx->format.speed) + sb->nbframes, sb->maxframes); return NULL; } newlength *= factor; // convert from sample frames to bytes @@ -649,14 +670,15 @@ qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *sfx) fs_offset_t filesize; ov_decode_t ov_decode; OggVorbis_File vf; - ogg_stream_persfx_t* per_sfx; vorbis_info *vi; vorbis_comment *vc; - ogg_int64_t len; + 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) @@ -694,27 +716,80 @@ qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *sfx) len = qov_pcm_total (&vf, -1) * vi->channels * 2; // 16 bits => "* 2" - if (developer_loading.integer >= 2) - Con_Printf ("Ogg sound file \"%s\" will be streamed\n", filename); - per_sfx = (ogg_stream_persfx_t *)Mem_Alloc (snd_mempool, sizeof (*per_sfx)); - strlcpy(per_sfx->name, sfx->name, sizeof(per_sfx->name)); - sfx->memsize += sizeof (*per_sfx); - per_sfx->file = data; - per_sfx->filesize = filesize; - sfx->memsize += filesize; - - per_sfx->format.speed = vi->rate; - per_sfx->format.width = 2; // We always work with 16 bits samples - per_sfx->format.channels = vi->channels; - - sfx->fetcher_data = per_sfx; - sfx->fetcher = &ogg_fetcher; - sfx->flags |= SFXFLAG_STREAMED; - sfx->total_length = (int)((size_t)len / (per_sfx->format.channels * 2) * ((double)snd_renderbuffer->format.speed / per_sfx->format.speed)); - vc = qov_comment(&vf, -1); - OGG_DecodeTags(vc, &sfx->loopstart, &sfx->total_length, (double)snd_renderbuffer->format.speed / (double)per_sfx->format.speed, sfx->total_length, &peak, &gaindb); - per_sfx->total_length = sfx->total_length; - qov_clear (&vf); + // 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 || snd_streaming.integer >= 2)) + { + ogg_stream_persfx_t* per_sfx; + + if (developer_loading.integer >= 2) + Con_Printf ("Ogg sound file \"%s\" will be streamed\n", filename); + per_sfx = (ogg_stream_persfx_t *)Mem_Alloc (snd_mempool, sizeof (*per_sfx)); + strlcpy(per_sfx->name, sfx->name, sizeof(per_sfx->name)); + sfx->memsize += sizeof (*per_sfx); + per_sfx->file = data; + per_sfx->filesize = filesize; + sfx->memsize += filesize; + + per_sfx->format.speed = vi->rate; + per_sfx->format.width = 2; // We always work with 16 bits samples + per_sfx->format.channels = vi->channels; + + sfx->fetcher_data = per_sfx; + sfx->fetcher = &ogg_fetcher; + sfx->flags |= SFXFLAG_STREAMED; + sfx->total_length = (int)((size_t)len / (per_sfx->format.channels * 2) * ((double)snd_renderbuffer->format.speed / per_sfx->format.speed)); + vc = qov_comment(&vf, -1); + OGG_DecodeTags(vc, &sfx->loopstart, &sfx->total_length, (double)snd_renderbuffer->format.speed / (double)per_sfx->format.speed, sfx->total_length, &peak, &gaindb); + per_sfx->total_length = sfx->total_length; + qov_clear (&vf); + } + else + { + char *buff; + ogg_int64_t done; + int bs; + long ret; + snd_buffer_t *sb; + snd_format_t ogg_format; + + if (developer_loading.integer >= 2) + Con_Printf ("Ogg sound file \"%s\" will be cached\n", filename); + + // Decode it + buff = (char *)Mem_Alloc (snd_mempool, (int)len); + done = 0; + bs = 0; + while ((ret = qov_read (&vf, &buff[done], (int)(len - done), mem_bigendian, 2, 1, &bs)) > 0) + done += ret; + + // Build the sound buffer + ogg_format.speed = vi->rate; + ogg_format.channels = vi->channels; + ogg_format.width = 2; // We always work with 16 bits samples + sb = Snd_CreateSndBuffer ((unsigned char *)buff, (size_t)done / (vi->channels * 2), &ogg_format, snd_renderbuffer->format.speed); + if (sb == NULL) + { + qov_clear (&vf); + Mem_Free (data); + Mem_Free (buff); + return false; + } + + sfx->fetcher = &wav_fetcher; + sfx->fetcher_data = sb; + + sfx->total_length = sb->nbframes; + sfx->memsize += sb->maxframes * sb->format.channels * sb->format.width + sizeof (*sb) - sizeof (sb->samples); + + sfx->flags &= ~SFXFLAG_STREAMED; + vc = qov_comment(&vf, -1); + OGG_DecodeTags(vc, &sfx->loopstart, &sfx->total_length, (double)snd_renderbuffer->format.speed / (double)sb->format.speed, sfx->total_length, &peak, &gaindb); + sb->nbframes = sfx->total_length; + qov_clear (&vf); + Mem_Free (data); + Mem_Free (buff); + } if(peak) {