From 6f2719e9f31ad130c0e7d5f00eb26d65f4550400 Mon Sep 17 00:00:00 2001 From: divverent Date: Sun, 2 Sep 2007 14:24:44 +0000 Subject: [PATCH] ReplayGain support for OggVorbis files (mostly useful for fake CD tracks) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@7553 d7cf8633-e32d-0410-b094-e92efae38249 --- snd_main.c | 14 +++++++++++++- snd_main.h | 3 +++ snd_mem.c | 3 +++ snd_ogg.c | 36 +++++++++++++++++++++++++++++------- 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/snd_main.c b/snd_main.c index ce790b34..93decebf 100644 --- a/snd_main.c +++ b/snd_main.c @@ -1172,7 +1172,6 @@ void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, // Initialize the channel memset (target_chan, 0, sizeof (*target_chan)); VectorCopy (origin, target_chan->origin); - target_chan->master_vol = (int)(fvol * 255); target_chan->sfx = sfx; target_chan->flags = flags; target_chan->pos = 0; // start of the sound @@ -1189,6 +1188,9 @@ void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, // Lock the SFX during play S_LockSfx (sfx); + + // and finally, apply the volume + S_SetChannelVolume(target_chan - channels, fvol); } @@ -1339,6 +1341,16 @@ void S_PauseGameSounds (qboolean toggle) void S_SetChannelVolume (unsigned int ch_ind, float fvol) { + sfx_t *sfx = channels[ch_ind].sfx; + if(sfx->volume_peak > 0) + { + // Replaygain support + // Con_DPrintf("Setting volume on ReplayGain-enabled track... %f -> ", fvol); + fvol *= sfx->volume_mult; + if(fvol * sfx->volume_peak > 1) + fvol = 1 / sfx->volume_peak; + // Con_DPrintf("%f\n", fvol); + } channels[ch_ind].master_vol = (int)(fvol * 255.0f); } diff --git a/snd_main.h b/snd_main.h index 3b53b62a..5efc8719 100644 --- a/snd_main.h +++ b/snd_main.h @@ -75,6 +75,9 @@ struct sfx_s unsigned int total_length; // in sample frames const snd_fetcher_t *fetcher; void *fetcher_data; // Per-sfx data for the sound fetching functions + + float volume_mult; // for replay gain (multiplier to apply) + float volume_peak; // for replay gain (highest peak); if set to 0, ReplayGain isn't supported }; // maximum supported speakers constant diff --git a/snd_mem.c b/snd_mem.c index 3da76b39..adb296ff 100644 --- a/snd_mem.c +++ b/snd_mem.c @@ -319,6 +319,9 @@ qboolean S_LoadSound (sfx_t *sfx, qboolean complain) if (snd_renderbuffer == NULL) return false; + // Initialize volume peak to 0; if ReplayGain is supported, the loader will change this away + sfx->volume_peak = 0.0; + // LordHavoc: if the sound filename does not begin with sound/, try adding it if (strncasecmp(sfx->name, "sound/", 6)) { diff --git a/snd_ogg.c b/snd_ogg.c index 28ccab1b..8abe92c4 100644 --- a/snd_ogg.c +++ b/snd_ogg.c @@ -622,13 +622,16 @@ Load an Ogg Vorbis file into memory qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *sfx) { unsigned char *data; - const char *loopcomment; + const char *thiscomment; 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 = 0.0; + double gaindb = 0.0; + double gain; if (!vf_dll) return false; @@ -694,9 +697,15 @@ qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *sfx) 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); + thiscomment = qvorbis_comment_query(vc, "LOOP_START", 0); + if(thiscomment) + sfx->loopstart = bound(0, (unsigned int) (atof(thiscomment) * (double)snd_renderbuffer->format.speed / (double)per_sfx->format.speed), sfx->total_length); + 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); } } else @@ -746,9 +755,15 @@ qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *sfx) 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); + thiscomment = qvorbis_comment_query(vc, "LOOP_START", 0); + if(thiscomment) + sfx->loopstart = bound(0, (unsigned int) (atoi(thiscomment) * (double)snd_renderbuffer->format.speed / (double)sb->format.speed), sfx->total_length); + 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); } qov_clear (&vf); @@ -756,5 +771,12 @@ qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *sfx) Mem_Free (buff); } + if(peak) + { + sfx->volume_mult = min(1 / peak, exp(gaindb * 0.05 * log(10))); + sfx->volume_peak = peak; + Con_DPrintf ("\"%s\" uses ReplayGain (gain %f, peak %f)\n", filename, sfx->volume_mult, sfx->volume_peak); + } + return true; } -- 2.39.2