shithub: choc

Download patch

ref: 4f16d8163cedb8b42ac01512c32a54023708b0ec
parent: 7db1399a0eb488fafbfc07ce6cf117f276ce03d9
author: Simon Howard <fraggle@gmail.com>
date: Mon Feb 11 17:59:51 EST 2008

Add support for sample rate conversion using libsamplerate (thanks to
David Flater for this patch).

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

--- a/configure.in
+++ b/configure.in
@@ -43,6 +43,9 @@
     exit -1
 ] ,$SDL_LIBS $SDLNET_LIBS)
 
+# DWF 2008-02-10:  FIXME
+AC_CHECK_LIB(samplerate, src_new)
+
 AC_CHECK_TOOL(WINDRES, windres, )
 
 AM_CONDITIONAL(HAVE_WINDRES, test "$WINDRES" != "")
--- a/src/i_sdlsound.c
+++ b/src/i_sdlsound.c
@@ -3,6 +3,7 @@
 //
 // Copyright(C) 1993-1996 Id Software, Inc.
 // Copyright(C) 2005 Simon Howard
+// Copyright(C) 2008 David Flater
 //
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU General Public License
@@ -25,11 +26,18 @@
 //-----------------------------------------------------------------------------
 
 
+#include "config.h"
+
 #include <stdio.h>
 #include <stdlib.h>
+#include <assert.h>
 #include "SDL.h"
 #include "SDL_mixer.h"
 
+#ifdef HAVE_LIBSAMPLERATE
+#include <samplerate.h>
+#endif
+
 #include "deh_main.h"
 #include "s_sound.h"
 #include "m_argv.h"
@@ -48,7 +56,11 @@
 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;
 
+int use_libsamplerate = 0;
+
 // When a sound stops, check if it is still playing.  If it is not, 
 // we can mark the sound data as CACHE to be freed back for other
 // means.
@@ -78,6 +90,72 @@
     Z_ChangeTag(sound_chunks[id].abuf, PU_CACHE);
 }
 
+#ifdef HAVE_LIBSAMPLERATE
+
+// libsamplerate-based generic sound expansion function for any sample rate
+//   unsigned 8 bits --> signed 16 bits
+//   mono --> stereo
+//   samplerate --> mixer_freq
+// Rewritten by DWF 2008-02-10:
+
+static void ExpandSoundData_SRC(byte *data,
+                                int samplerate,
+                                int length,
+                                Mix_Chunk *destination)
+{
+    SRC_DATA src_data;
+    uint32_t i, abuf_index=0;
+    int retn;
+    int16_t *expanded;
+
+    src_data.input_frames = length;
+    src_data.data_in = malloc(length * sizeof(float));
+    src_data.src_ratio = (double)mixer_freq / samplerate;
+    src_data.output_frames = src_data.src_ratio * length + samplerate;
+    src_data.data_out = malloc(src_data.output_frames * sizeof(float));
+
+    assert(src_data.data_in != NULL && src_data.data_out != NULL);
+
+    // Convert input data to floats
+
+    for (i=0; i<length; ++i)
+    {
+        src_data.data_in[i] = data[i] / 127.5 - 1;
+    }
+
+    // Do the sound conversion
+
+    retn = src_simple(&src_data, SRC_SINC_MEDIUM_QUALITY, 1);
+    assert(retn == 0);
+
+    // Convert the result back into 16-bit integers.
+
+    destination->alen = src_data.output_frames_gen * 4;
+    destination->abuf = Z_Malloc(destination->alen, PU_STATIC, 
+                                 &destination->abuf);
+    expanded = (int16_t *) destination->abuf;
+
+    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.
+
+        float cvtval = src_data.data_out[i] * 20000;
+        cvtval += (cvtval < 0 ? -0.5 : 0.5);
+
+        // Left and right channels
+
+        expanded[abuf_index++] = cvtval;
+        expanded[abuf_index++] = cvtval;
+    }
+
+    free(src_data.data_in);
+    free(src_data.data_out);
+}
+
+#endif
+
 static boolean ConvertibleRatio(int freq1, int freq2)
 {
     int ratio;
@@ -109,12 +187,27 @@
 
 // Generic sound expansion function for any sample rate
 
-static void ExpandSoundData(byte *data,
-                            int samplerate,
-                            int length,
-                            Mix_Chunk *destination)
+static void ExpandSoundData_SDL(byte *data,
+                                int samplerate,
+                                int length,
+                                Mix_Chunk *destination)
 {
     SDL_AudioCVT convertor;
+    uint32_t expanded_length;
+ 
+    // Calculate the length of the expanded version of the sample.    
+
+    expanded_length = (uint32_t) ((((uint64_t) length) * mixer_freq) / samplerate);
+
+    // Double up twice: 8 -> 16 bit and mono -> stereo
+
+    expanded_length *= 4;
+
+    destination->alen = expanded_length;
+    destination->abuf 
+        = Z_Malloc(expanded_length, PU_STATIC, &destination->abuf);
+
+    // If we can, use the standard / optimised SDL conversion routines.
     
     if (samplerate <= mixer_freq
      && ConvertibleRatio(samplerate, mixer_freq)
@@ -172,7 +265,6 @@
     unsigned int lumplen;
     int samplerate;
     unsigned int length;
-    unsigned int expanded_length;
     byte *data;
 
     // need to load the sound
@@ -205,19 +297,11 @@
     }
 
     // Sample rate conversion
+    // DWF 2008-02-10:  sound_chunks[sound].alen and abuf are determined
+    // by ExpandSoundData.
 
-    expanded_length = (uint32_t) ((((uint64_t) length) * mixer_freq) / samplerate);
-
-    // Double up twice: 8 -> 16 bit and mono -> stereo
-
-    expanded_length *= 4;
-
     sound_chunks[sound].allocated = 1;
-    sound_chunks[sound].alen = expanded_length;
-    sound_chunks[sound].abuf 
-        = Z_Malloc(expanded_length, PU_STATIC, &sound_chunks[sound].abuf);
     sound_chunks[sound].volume = MIX_MAX_VOLUME;
-
     ExpandSoundData(data + 8, 
                     samplerate, 
                     length, 
@@ -415,6 +499,15 @@
         fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError());
         return false;
     }
+
+    ExpandSoundData = ExpandSoundData_SDL;
+
+#ifdef HAVE_LIBSAMPLERATE
+    if (use_libsamplerate)
+    {
+        ExpandSoundData = ExpandSoundData_SRC;
+    }
+#endif
 
     Mix_QuerySpec(&mixer_freq, &mixer_format, &mixer_channels);
 
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -299,6 +299,10 @@
 extern int snd_sfxdevice;
 extern int snd_samplerate;
 
+// controls whether to use libsamplerate for sample rate conversions
+
+extern int use_libsamplerate;
+
 // dos specific options: these are unused but should be maintained
 // so that the config file can be shared between chocolate
 // doom and doom.exe
@@ -444,6 +448,7 @@
     {"mouseb_backward",             &mousebbackward, DEFAULT_INT, 0, 0},
 
     {"dclick_use",                  &dclick_use, DEFAULT_INT, 0, 0},
+    {"use_libsamplerate",           &use_libsamplerate, DEFAULT_INT, 0, 0},
 };
 
 static default_collection_t extra_defaults =