shithub: choc

Download patch

ref: de318a6f06dd24136a3d538a27ecef43a1bce1e5
parent: 0b01221f1bc6dd40e918d2d19a7c62896b057744
author: Simon Howard <fraggle@gmail.com>
date: Thu Mar 13 14:33:59 EDT 2008

Apply SRC patch from David Flater.

Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 1105

--- a/src/i_sdlsound.c
+++ b/src/i_sdlsound.c
@@ -57,8 +57,8 @@
 static int mixer_freq;
 static Uint16 mixer_format;
 static int mixer_channels;
-static void (*ExpandSoundData)(byte *data, int samplerate, int length,
-                               Mix_Chunk *destination) = NULL;
+static uint32_t (*ExpandSoundData)(byte *data, int samplerate, int length,
+                                   Mix_Chunk *destination) = NULL;
 
 int use_libsamplerate = 0;
 
@@ -97,15 +97,16 @@
 //   unsigned 8 bits --> signed 16 bits
 //   mono --> stereo
 //   samplerate --> mixer_freq
+// Returns number of clipped samples.
 // DWF 2008-02-10 with cleanups by Simon Howard.
 
-static void ExpandSoundData_SRC(byte *data,
-                                int samplerate,
-                                int length,
-                                Mix_Chunk *destination)
+static uint32_t ExpandSoundData_SRC(byte *data,
+                                    int samplerate,
+                                    int length,
+                                    Mix_Chunk *destination)
 {
     SRC_DATA src_data;
-    uint32_t i, abuf_index=0;
+    uint32_t i, abuf_index=0, clipped=0;
     int retn;
     int16_t *expanded;
 
@@ -123,12 +124,15 @@
 
     for (i=0; i<length; ++i)
     {
+        // Unclear whether 128 should be interpreted as "zero" or whether a
+        // symmetrical range should be assumed.  The following assumes a
+        // symmetrical range.
         src_data.data_in[i] = data[i] / 127.5 - 1;
     }
 
     // Do the sound conversion
 
-    retn = src_simple(&src_data, SRC_SINC_FASTEST, 1);
+    retn = src_simple(&src_data, SRC_SINC_BEST_QUALITY, 1);
     assert(retn == 0);
 
     // Convert the result back into 16-bit integers.
@@ -140,21 +144,48 @@
 
     for (i=0; i<src_data.output_frames_gen; ++i)
     {
-        // libsamplerate does not limit itself to the -1.0 .. 1.0 range
-        // on output, so some slack is required to avoid overflows or
-        // clipping.  The amount of slack is a fudge factor.
+        // libsamplerate does not limit itself to the -1.0 .. 1.0 range on
+        // output, so a multiplier less than INT16_MAX (32767) is required
+        // to avoid overflows or clipping.  However, the smaller the
+        // multiplier, the quieter the sound effects get, and the more you
+        // have to turn down the music to keep it in balance.
 
-        float cvtval = src_data.data_out[i] * 20000;
-        cvtval += (cvtval < 0 ? -0.5 : 0.5);
+        // 22265 is the largest multiplier that can be used to resample all
+        // of the Vanilla DOOM sound effects to 48 kHz without clipping
+        // using SRC_SINC_BEST_QUALITY.  It is close enough (only slightly
+        // too conservative) for SRC_SINC_MEDIUM_QUALITY and
+        // SRC_SINC_FASTEST.  PWADs with interestingly different sound
+        // effects or target rates other than 48 kHz might still result in
+        // clipping--I don't know if there's a limit to it.
 
+        // As the number of clipped samples increases, the signal is
+        // gradually overtaken by noise, with the loudest parts going first.
+        // However, a moderate amount of clipping is often tolerated in the
+        // quest for the loudest possible sound overall.  The results of
+        // using INT16_MAX as the multiplier are not all that bad, but
+        // artifacts are noticeable during the loudest parts.
+
+        float   cvtval_f = src_data.data_out[i] * 22265;
+        int32_t cvtval_i = cvtval_f + (cvtval_f < 0 ? -0.5 : 0.5);
+
+        // Asymmetrical sound worries me, so we won't use -32768.
+        if (cvtval_i < -INT16_MAX) {
+          cvtval_i = -INT16_MAX;
+          ++clipped;
+        } else if (cvtval_i > INT16_MAX) {
+          cvtval_i = INT16_MAX;
+          ++clipped;
+        }
+
         // Left and right channels
 
-        expanded[abuf_index++] = cvtval;
-        expanded[abuf_index++] = cvtval;
+        expanded[abuf_index++] = cvtval_i;
+        expanded[abuf_index++] = cvtval_i;
     }
 
     free(src_data.data_in);
     free(src_data.data_out);
+    return clipped;
 }
 
 #endif
@@ -188,12 +219,13 @@
     }
 }
 
-// Generic sound expansion function for any sample rate
+// Generic sound expansion function for any sample rate.
+// Returns number of clipped samples (always 0).
 
-static void ExpandSoundData_SDL(byte *data,
-                                int samplerate,
-                                int length,
-                                Mix_Chunk *destination)
+static uint32_t ExpandSoundData_SDL(byte *data,
+                                    int samplerate,
+                                    int length,
+                                    Mix_Chunk *destination)
 {
     SDL_AudioCVT convertor;
     uint32_t expanded_length;
@@ -284,6 +316,8 @@
         }
 #endif /* #ifdef LOW_PASS_FILTER */
     }
+
+    return 0;
 }
 
 // Load and convert a sound effect
@@ -294,6 +328,7 @@
     int lumpnum;
     unsigned int lumplen;
     int samplerate;
+    int clipped;
     unsigned int length;
     byte *data;
 
@@ -332,10 +367,18 @@
 
     sound_chunks[sound].allocated = 1;
     sound_chunks[sound].volume = MIX_MAX_VOLUME;
-    ExpandSoundData(data + 8, 
-                    samplerate, 
-                    length, 
-                    &sound_chunks[sound]);
+
+    clipped = ExpandSoundData(data + 8, 
+                              samplerate, 
+                              length, 
+                              &sound_chunks[sound]);
+
+    if (clipped)
+    {
+        fprintf(stderr, "Sound %d: clipped %u samples (%0.2f %%)\n", 
+                        sound, clipped,
+                        400.0 * clipped / sound_chunks[sound].alen);
+    }
 
     // don't need the original lump any more