extern cvar_t v_flipped;
cvar_t snd_channellayout = {0, "snd_channellayout", "0", "channel layout. Can be 0 (auto - snd_restart needed), 1 (standard layout), or 2 (ALSA layout)"};
cvar_t snd_mutewhenidle = {CVAR_SAVE, "snd_mutewhenidle", "1", "whether to disable sound output when game window is inactive"};
+cvar_t snd_maxchannelvolume = {CVAR_SAVE, "snd_maxchannelvolume", "10", "maximum volume of a single sound"};
+cvar_t snd_softclip = {CVAR_SAVE, "snd_softclip", "0", "Use soft-clipping. Soft-clipping can make the sound more smooth if very high volume levels are used. Enable this option if the dynamic range of the loudspeakers is very low. WARNING: This feature creates distortion and should be considered a last resort."};
+//cvar_t snd_softclip = {CVAR_SAVE, "snd_softclip", "0", "Use soft-clipping (when set to 2, use it even if output is floating point). Soft-clipping can make the sound more smooth if very high volume levels are used. Enable this option if the dynamic range of the loudspeakers is very low. WARNING: This feature creates distortion and should be considered a last resort."};
cvar_t snd_entchannel0volume = {CVAR_SAVE, "snd_entchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of regular entities (DEPRECATED)"};
cvar_t snd_entchannel1volume = {CVAR_SAVE, "snd_entchannel1volume", "1", "volume multiplier of the 1st entity channel of regular entities (DEPRECATED)"};
cvar_t snd_entchannel2volume = {CVAR_SAVE, "snd_entchannel2volume", "1", "volume multiplier of the 2nd entity channel of regular entities (DEPRECATED)"};
Cvar_RegisterVariable(&snd_width);
Cvar_RegisterVariable(&snd_channels);
Cvar_RegisterVariable(&snd_mutewhenidle);
+ Cvar_RegisterVariable(&snd_maxchannelvolume);
+ Cvar_RegisterVariable(&snd_softclip);
Cvar_RegisterVariable(&snd_startloopingsounds);
Cvar_RegisterVariable(&snd_startnonloopingsounds);
if (!(ch->flags & CHANNELFLAG_FULLVOLUME))
mastervol *= volume.value;
- // clamp HERE to allow to go at most 10dB past mastervolume (before clamping), when mastervolume < -10dB (so relative volumes don't get too messy)
- mastervol = bound(0.0f, mastervol, 10.0f);
+ if(snd_maxchannelvolume.value > 0)
+ {
+ // clamp HERE to allow to go at most 10dB past mastervolume (before clamping), when mastervolume < -10dB (so relative volumes don't get too messy)
+ mastervol = bound(0.0f, mastervol, 10.0f * snd_maxchannelvolume.value);
+ }
// always apply "master"
mastervol *= mastervolume.value;
// Replaygain support
// Con_DPrintf("Setting volume on ReplayGain-enabled track... %f -> ", fvol);
mastervol *= sfx->volume_mult;
- if(mastervol * sfx->volume_peak > 1.0f)
- mastervol = 1.0f / sfx->volume_peak;
+ if(snd_maxchannelvolume.value > 0)
+ {
+ if(mastervol * sfx->volume_peak > snd_maxchannelvolume.value)
+ mastervol = snd_maxchannelvolume.value / sfx->volume_peak;
+ }
// Con_DPrintf("%f\n", fvol);
}
- // clamp HERE to keep relative volumes of the channels correct
- mastervol = bound(0.0f, mastervol, 1.0f);
+ if(snd_maxchannelvolume.value > 0)
+ {
+ // clamp HERE to keep relative volumes of the channels correct
+ mastervol = min(mastervol, snd_maxchannelvolume.value);
+ }
+
+ mastervol = max(0.0f, mastervol);
ch->mixspeed = mixspeed;
#include "quakedef.h"
#include "snd_main.h"
+extern cvar_t snd_softclip;
static portable_sampleframe_t paintbuffer[PAINTBUFFER_SIZE];
static portable_sampleframe_t paintbuffer_unswapped[PAINTBUFFER_SIZE];
SCR_CaptureVideo_SoundFrame(paintbuffer_unswapped, length);
}
-static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void *rb_ptr, int nbframes, int width, int channels)
+extern cvar_t snd_softclip;
+
+static void S_SoftClipPaintBuffer(portable_sampleframe_t *painted_ptr, int nbframes, int width, int channels)
+{
+ int i;
+
+ if((snd_softclip.integer == 1 && width <= 2) || snd_softclip.integer > 1)
+ {
+#if 0
+/* Soft clipping, the sound of a dream, thanks to Jon Wattes
+ post to Musicdsp.org */
+#define SOFTCLIP(x) (x) = sin(bound(-M_PI/2, (x), M_PI/2)) * 0.25
+#endif
+
+ // let's do a simple limiter instead, seems to sound better
+ static float maxvol = 0;
+ maxvol = max(1.0f, maxvol * (1.0f - nbframes / snd_renderbuffer->format.speed));
+#define SOFTCLIP(x) if((x)>maxvol) maxvol=(x); (x) /= maxvol;
+
+ portable_sampleframe_t *p = painted_ptr;
+ if (channels == 8) // 7.1 surround
+ {
+ for (i = 0;i < nbframes;i++, p++)
+ {
+ SOFTCLIP(p->sample[0]);
+ SOFTCLIP(p->sample[1]);
+ SOFTCLIP(p->sample[2]);
+ SOFTCLIP(p->sample[3]);
+ SOFTCLIP(p->sample[4]);
+ SOFTCLIP(p->sample[5]);
+ SOFTCLIP(p->sample[6]);
+ SOFTCLIP(p->sample[7]);
+ }
+ }
+ else if (channels == 6) // 5.1 surround
+ {
+ for (i = 0; i < nbframes; i++, p++)
+ {
+ SOFTCLIP(p->sample[0]);
+ SOFTCLIP(p->sample[1]);
+ SOFTCLIP(p->sample[2]);
+ SOFTCLIP(p->sample[3]);
+ SOFTCLIP(p->sample[4]);
+ SOFTCLIP(p->sample[5]);
+ }
+ }
+ else if (channels == 4) // 4.0 surround
+ {
+ for (i = 0; i < nbframes; i++, p++)
+ {
+ SOFTCLIP(p->sample[0]);
+ SOFTCLIP(p->sample[1]);
+ SOFTCLIP(p->sample[2]);
+ SOFTCLIP(p->sample[3]);
+ }
+ }
+ else if (channels == 2) // 2.0 stereo
+ {
+ for (i = 0; i < nbframes; i++, p++)
+ {
+ SOFTCLIP(p->sample[0]);
+ SOFTCLIP(p->sample[1]);
+ }
+ }
+ else if (channels == 1) // 1.0 mono
+ {
+ for (i = 0; i < nbframes; i++, p++)
+ {
+ SOFTCLIP(p->sample[0]);
+ }
+ }
+#undef SOFTCLIP
+ }
+}
+
+static void S_ConvertPaintBuffer(portable_sampleframe_t *painted_ptr, void *rb_ptr, int nbframes, int width, int channels)
{
int i, val;
+
// FIXME: add 24bit and 32bit float formats
// FIXME: optimize with SSE intrinsics?
if (width == 2) // 16bit
S_StopChannel(ch - channels, false, false);
}
+ S_SoftClipPaintBuffer(paintbuffer, totalmixframes, snd_renderbuffer->format.width, snd_renderbuffer->format.channels);
+
if (!snd_usethreadedmixing)
S_CaptureAVISound(paintbuffer, totalmixframes);