]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - snd_mix.c
README: Add link to Matrix space
[xonotic/darkplaces.git] / snd_mix.c
index 35add4ef72a2570598d38932765f383cc51ecb4a..736d6ea1964f54ab7d11485daafde3d5d498f039 100644 (file)
--- a/snd_mix.c
+++ b/snd_mix.c
@@ -21,14 +21,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #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];
 
 extern speakerlayout_t snd_speakerlayout; // for querying the listeners
 
-extern void SCR_CaptureVideo_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length);
-static void S_CaptureAVISound(const portable_sampleframe_t *paintbuffer, size_t length)
+#ifdef CONFIG_VIDEO_CAPTURE
+static portable_sampleframe_t paintbuffer_unswapped[PAINTBUFFER_SIZE];
+
+static void S_CaptureAVISound(const portable_sampleframe_t *sampleframes, size_t length)
 {
        size_t i;
        unsigned int j;
@@ -41,21 +43,156 @@ static void S_CaptureAVISound(const portable_sampleframe_t *paintbuffer, size_t
        {
                unsigned int j0 = snd_speakerlayout.listeners[j].channel_unswapped;
                for(i = 0; i < length; ++i)
-                       paintbuffer_unswapped[i].sample[j0] = paintbuffer[i].sample[j];
+                       paintbuffer_unswapped[i].sample[j0] = sampleframes[i].sample[j];
        }
 
        SCR_CaptureVideo_SoundFrame(paintbuffer_unswapped, length);
 }
+#endif
+
+extern cvar_t snd_softclip;
 
-static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void *rb_ptr, int nbframes, int width, int channels)
+static void S_SoftClipPaintBuffer(portable_sampleframe_t *painted_ptr, int nbframes, int width, int nchannels)
 {
-       int i, val;
-       // FIXME: add 24bit and 32bit float formats
-       // FIXME: optimize with SSE intrinsics?
-       if (width == 2)  // 16bit
+       int i;
+
+       if((snd_softclip.integer == 1 && width <= 2) || snd_softclip.integer > 1)
+       {
+               portable_sampleframe_t *p = painted_ptr;
+
+#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 / (0.4f * snd_renderbuffer->format.speed)));
+#define SOFTCLIP(x) if(fabs(x)>maxvol) maxvol=fabs(x); (x) /= maxvol;
+
+               if (nchannels == 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 (nchannels == 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 (nchannels == 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 (nchannels == 2)  // 2.0 stereo
+               {
+                       for (i = 0; i < nbframes; i++, p++)
+                       {
+                               SOFTCLIP(p->sample[0]);
+                               SOFTCLIP(p->sample[1]);
+                       }
+               }
+               else if (nchannels == 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 nchannels)
+{
+       int i;
+       float val;
+       if (width == 4)  // 32bit float
+       {
+               float *snd_out = (float*)rb_ptr;
+               if (nchannels == 8)  // 7.1 surround
+               {
+                       for (i = 0; i < nbframes; i++, painted_ptr++)
+                       {
+                               *snd_out++ = painted_ptr->sample[0];
+                               *snd_out++ = painted_ptr->sample[1];
+                               *snd_out++ = painted_ptr->sample[2];
+                               *snd_out++ = painted_ptr->sample[3];
+                               *snd_out++ = painted_ptr->sample[4];
+                               *snd_out++ = painted_ptr->sample[5];
+                               *snd_out++ = painted_ptr->sample[6];
+                               *snd_out++ = painted_ptr->sample[7];
+                       }
+               }
+               else if (nchannels == 6)  // 5.1 surround
+               {
+                       for (i = 0; i < nbframes; i++, painted_ptr++)
+                       {
+                               *snd_out++ = painted_ptr->sample[0];
+                               *snd_out++ = painted_ptr->sample[1];
+                               *snd_out++ = painted_ptr->sample[2];
+                               *snd_out++ = painted_ptr->sample[3];
+                               *snd_out++ = painted_ptr->sample[4];
+                               *snd_out++ = painted_ptr->sample[5];
+                       }
+               }
+               else if (nchannels == 4)  // 4.0 surround
+               {
+                       for (i = 0; i < nbframes; i++, painted_ptr++)
+                       {
+                               *snd_out++ = painted_ptr->sample[0];
+                               *snd_out++ = painted_ptr->sample[1];
+                               *snd_out++ = painted_ptr->sample[2];
+                               *snd_out++ = painted_ptr->sample[3];
+                       }
+               }
+               else if (nchannels == 2)  // 2.0 stereo
+               {
+                       for (i = 0; i < nbframes; i++, painted_ptr++)
+                       {
+                               *snd_out++ = painted_ptr->sample[0];
+                               *snd_out++ = painted_ptr->sample[1];
+                       }
+               }
+               else if (nchannels == 1)  // 1.0 mono
+               {
+                       for (i = 0; i < nbframes; i++, painted_ptr++)
+                       {
+                               *snd_out++ = painted_ptr->sample[0];
+                       }
+               }
+
+               // noise is really really annoying
+               if (cls.timedemo)
+                       memset(rb_ptr, 0, nbframes * nchannels * width);
+       }
+       else if (width == 2)  // 16bit
        {
                short *snd_out = (short*)rb_ptr;
-               if (channels == 8)  // 7.1 surround
+               if (nchannels == 8)  // 7.1 surround
                {
                        for (i = 0;i < nbframes;i++, painted_ptr++)
                        {
@@ -69,7 +206,7 @@ static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void
                                val = (int)(painted_ptr->sample[7] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
                        }
                }
-               else if (channels == 6)  // 5.1 surround
+               else if (nchannels == 6)  // 5.1 surround
                {
                        for (i = 0; i < nbframes; i++, painted_ptr++)
                        {
@@ -81,7 +218,7 @@ static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void
                                val = (int)(painted_ptr->sample[5] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
                        }
                }
-               else if (channels == 4)  // 4.0 surround
+               else if (nchannels == 4)  // 4.0 surround
                {
                        for (i = 0; i < nbframes; i++, painted_ptr++)
                        {
@@ -91,7 +228,7 @@ static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void
                                val = (int)(painted_ptr->sample[3] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
                        }
                }
-               else if (channels == 2)  // 2.0 stereo
+               else if (nchannels == 2)  // 2.0 stereo
                {
                        for (i = 0; i < nbframes; i++, painted_ptr++)
                        {
@@ -99,7 +236,7 @@ static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void
                                val = (int)(painted_ptr->sample[1] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
                        }
                }
-               else if (channels == 1)  // 1.0 mono
+               else if (nchannels == 1)  // 1.0 mono
                {
                        for (i = 0; i < nbframes; i++, painted_ptr++)
                        {
@@ -109,12 +246,12 @@ static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void
 
                // noise is really really annoying
                if (cls.timedemo)
-                       memset(rb_ptr, 0, nbframes * channels * width);
+                       memset(rb_ptr, 0, nbframes * nchannels * width);
        }
        else  // 8bit
        {
                unsigned char *snd_out = (unsigned char*)rb_ptr;
-               if (channels == 8)  // 7.1 surround
+               if (nchannels == 8)  // 7.1 surround
                {
                        for (i = 0; i < nbframes; i++, painted_ptr++)
                        {
@@ -128,7 +265,7 @@ static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void
                                val = (int)(painted_ptr->sample[7] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
                        }
                }
-               else if (channels == 6)  // 5.1 surround
+               else if (nchannels == 6)  // 5.1 surround
                {
                        for (i = 0; i < nbframes; i++, painted_ptr++)
                        {
@@ -140,7 +277,7 @@ static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void
                                val = (int)(painted_ptr->sample[5] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
                        }
                }
-               else if (channels == 4)  // 4.0 surround
+               else if (nchannels == 4)  // 4.0 surround
                {
                        for (i = 0; i < nbframes; i++, painted_ptr++)
                        {
@@ -150,7 +287,7 @@ static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void
                                val = (int)(painted_ptr->sample[3] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
                        }
                }
-               else if (channels == 2)  // 2.0 stereo
+               else if (nchannels == 2)  // 2.0 stereo
                {
                        for (i = 0; i < nbframes; i++, painted_ptr++)
                        {
@@ -158,7 +295,7 @@ static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void
                                val = (int)(painted_ptr->sample[1] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
                        }
                }
-               else if (channels == 1)  // 1.0 mono
+               else if (nchannels == 1)  // 1.0 mono
                {
                        for (i = 0;i < nbframes;i++, painted_ptr++)
                        {
@@ -168,7 +305,7 @@ static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void
 
                // noise is really really annoying
                if (cls.timedemo)
-                       memset(rb_ptr, 128, nbframes * channels);
+                       memset(rb_ptr, 128, nbframes * nchannels);
        }
 }
 
@@ -210,8 +347,8 @@ void S_MixToBuffer(void *stream, unsigned int bufferframes)
        double posd;
        double speedd;
        float maxvol;
-       qboolean looping;
-       qboolean silent;
+       qbool looping;
+       qbool silent;
 
        // mix as many times as needed to fill the requested buffer
        while (bufferframes)
@@ -224,7 +361,7 @@ void S_MixToBuffer(void *stream, unsigned int bufferframes)
 
                // paint in the channels.
                // channels with zero volumes still advance in time but don't paint.
-               ch = channels;
+               ch = channels; // cppcheck complains here but it is wrong, channels is a channel_t[MAX_CHANNELS] and not an int
                for (channelindex = 0;channelindex < (int)total_channels;channelindex++, ch++)
                {
                        sfx = ch->sfx;
@@ -283,7 +420,6 @@ void S_MixToBuffer(void *stream, unsigned int bufferframes)
 
                        // do the actual paint now (may skip work if silent)
                        paint = paintbuffer;
-                       wantframes = totalmixframes;
                        istartframe = 0;
                        for (wantframes = totalmixframes;wantframes > 0;posd += count * speedd, wantframes -= count)
                        {
@@ -442,8 +578,12 @@ void S_MixToBuffer(void *stream, unsigned int bufferframes)
                                S_StopChannel(ch - channels, false, false);
                }
 
+               S_SoftClipPaintBuffer(paintbuffer, totalmixframes, snd_renderbuffer->format.width, snd_renderbuffer->format.channels);
+
+#ifdef CONFIG_VIDEO_CAPTURE
                if (!snd_usethreadedmixing)
                        S_CaptureAVISound(paintbuffer, totalmixframes);
+#endif
 
                S_ConvertPaintBuffer(paintbuffer, outbytes, totalmixframes, snd_renderbuffer->format.width, snd_renderbuffer->format.channels);