ref: de318a6f06dd24136a3d538a27ecef43a1bce1e5
parent: 0b01221f1bc6dd40e918d2d19a7c62896b057744
author: Simon Howard <[email protected]>
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