// Load the DLLs
// We need to load both by hand because some OSes seem to not load
// the vorbis DLL automatically when loading the VorbisFile DLL
- if (! Sys_LoadLibrary (dllnames_vo, &vo_dll, vorbisfuncs) ||
- ! Sys_LoadLibrary (dllnames_vf, &vf_dll, vorbisfilefuncs))
- {
- Sys_UnloadLibrary (&vo_dll);
- Con_Printf ("Ogg Vorbis support disabled\n");
- return false;
- }
-
- Con_Printf ("Ogg Vorbis support enabled\n");
- return true;
+ return Sys_LoadLibrary (dllnames_vo, &vo_dll, vorbisfuncs) && Sys_LoadLibrary (dllnames_vf, &vf_dll, vorbisfilefuncs);
}
}
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",
OGG_FetchEnd
====================
*/
-static void OGG_FetchEnd (void **chfetcherpointer)
+static void OGG_FetchEnd (void *chfetcherdata)
{
- ogg_stream_perchannel_t* per_ch = (ogg_stream_perchannel_t *)*chfetcherpointer;
+ ogg_stream_perchannel_t* per_ch = (ogg_stream_perchannel_t *)chfetcherdata;
if (per_ch != NULL)
{
Mem_Free (per_ch);
}
- *chfetcherpointer = NULL;
}
OGG_FreeSfx
====================
*/
-static void OGG_FreeSfx (sfx_t* sfx)
+static void OGG_FreeSfx (void *sfxfetcherdata)
{
- ogg_stream_persfx_t* per_sfx = (ogg_stream_persfx_t *)sfx->fetcher_data;
+ ogg_stream_persfx_t* per_sfx = (ogg_stream_persfx_t *)sfxfetcherdata;
// Free the Ogg Vorbis file
Mem_Free(per_sfx->file);
- sfx->memsize -= per_sfx->filesize;
// Free the stream structure
Mem_Free(per_sfx);
- sfx->memsize -= sizeof (*per_sfx);
-
- sfx->fetcher_data = NULL;
- sfx->fetcher = NULL;
}
static const snd_fetcher_t ogg_fetcher = { OGG_FetchSound, OGG_FetchEnd, OGG_FreeSfx, OGG_GetFormat };
+static void OGG_DecodeTags(vorbis_comment *vc, unsigned int *start, unsigned int *length, double samplesfactor, unsigned int numsamples, double *peak, double *gaindb)
+{
+ const char *startcomment = NULL, *lengthcomment = NULL, *endcomment = NULL, *thiscomment = NULL;
+
+ *start = numsamples;
+ *length = numsamples;
+ *peak = 0.0;
+ *gaindb = 0.0;
+
+ if(!vc)
+ return;
+
+ thiscomment = qvorbis_comment_query(vc, "REPLAYGAIN_TRACK_PEAK", 0);
+ if(thiscomment)
+ *peak = atof(thiscomment);
+ thiscomment = qvorbis_comment_query(vc, "REPLAYGAIN_TRACK_GAIN", 0);
+ if(thiscomment)
+ *gaindb = atof(thiscomment);
+
+ startcomment = qvorbis_comment_query(vc, "LOOP_START", 0); // DarkPlaces, and some Japanese app
+ if(startcomment)
+ {
+ endcomment = qvorbis_comment_query(vc, "LOOP_END", 0);
+ if(!endcomment)
+ lengthcomment = qvorbis_comment_query(vc, "LOOP_LENGTH", 0);
+ }
+ else
+ {
+ startcomment = qvorbis_comment_query(vc, "LOOPSTART", 0); // RPG Maker VX
+ if(startcomment)
+ {
+ lengthcomment = qvorbis_comment_query(vc, "LOOPLENGTH", 0);
+ if(!lengthcomment)
+ endcomment = qvorbis_comment_query(vc, "LOOPEND", 0);
+ }
+ else
+ {
+ startcomment = qvorbis_comment_query(vc, "LOOPPOINT", 0); // Sonic Robo Blast 2
+ }
+ }
+
+ if(startcomment)
+ {
+ *start = (unsigned int) bound(0, atof(startcomment) * samplesfactor, numsamples);
+ if(endcomment)
+ *length = (unsigned int) bound(0, atof(endcomment) * samplesfactor, numsamples);
+ else if(lengthcomment)
+ *length = (unsigned int) bound(0, *start + atof(lengthcomment) * samplesfactor, numsamples);
+ }
+}
/*
====================
qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *sfx)
{
unsigned char *data;
- const char *loopcomment;
fs_offset_t filesize;
ov_decode_t ov_decode;
OggVorbis_File vf;
vorbis_info *vi;
vorbis_comment *vc;
ogg_int64_t len, buff_len;
+ double peak, gaindb;
if (!vf_dll)
return false;
if (data == NULL)
return false;
- Con_DPrintf ("Loading Ogg Vorbis file \"%s\"\n", filename);
+ if (developer_loading.integer >= 2)
+ Con_Printf ("Loading Ogg Vorbis file \"%s\"\n", filename);
// Open it with the VorbisFile API
ov_decode.buffer = data;
{
ogg_stream_persfx_t* per_sfx;
- Con_DPrintf ("\"%s\" will be streamed\n", filename);
+ 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);
sfx->fetcher_data = per_sfx;
sfx->fetcher = &ogg_fetcher;
sfx->flags |= SFXFLAG_STREAMED;
- per_sfx->total_length = sfx->total_length = (int)((size_t)len / (per_sfx->format.channels * 2) * ((double)snd_renderbuffer->format.speed / per_sfx->format.speed));
- sfx->loopstart = sfx->total_length;
+ 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);
- if(vc)
- {
- loopcomment = qvorbis_comment_query(vc, "LOOP_START", 0);
- if(loopcomment)
- sfx->loopstart = bound(0, (unsigned int) (atof(loopcomment) * (double)snd_renderbuffer->format.speed / (double)per_sfx->format.speed), sfx->total_length);
- }
+ 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
{
snd_buffer_t *sb;
snd_format_t ogg_format;
- Con_DPrintf ("\"%s\" will be cached\n", filename);
+ 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);
sfx->total_length = sb->nbframes;
sfx->memsize += sb->maxframes * sb->format.channels * sb->format.width + sizeof (*sb) - sizeof (sb->samples);
- sfx->loopstart = sfx->total_length;
sfx->flags &= ~SFXFLAG_STREAMED;
vc = qov_comment(&vf, -1);
- if(vc)
- {
- loopcomment = qvorbis_comment_query(vc, "LOOP_START", 0);
- if(loopcomment)
- sfx->loopstart = bound(0, (unsigned int) (atoi(loopcomment) * (double)snd_renderbuffer->format.speed / (double)sb->format.speed), sfx->total_length);
- }
-
+ 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)
+ {
+ 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);
+ }
+
return true;
}