--- ../../../gst-plugins-base-0.10.13/gst/volume/gstvolume.c	2007-06-08 11:14:10.000000000 +0800
+++ gstvolume.c	2007-06-09 22:11:28.000000000 +0800
@@ -60,9 +60,17 @@
  */
 #define VOLUME_UNITY_INT16           8192       /* internal int for unity 2^13 */
 #define VOLUME_UNITY_INT16_BIT_SHIFT 13 /* number of bits to shift for unity */
+#define VOLUME_UNITY_INT32           8192       /* how to choose this value? */
+#define VOLUME_UNITY_INT32_BIT_SHIFT 13
+#define VOLUME_UNITY_INT24           8192       /* and this one? */
+#define VOLUME_UNITY_INT24_BIT_SHIFT 13
 #define VOLUME_MAX_DOUBLE            10.0
 #define VOLUME_MAX_INT16             32767
 #define VOLUME_MIN_INT16             -32768
+#define VOLUME_MAX_INT32             2147483647
+#define VOLUME_MIN_INT32             -2147483646
+#define VOLUME_MAX_INT24             8388607
+#define VOLUME_MIN_INT24             -8388606
 
 /* number of steps we use for the mixer interface to go from 0.0 to 1.0 */
 # define VOLUME_STEPS           100
@@ -103,7 +111,7 @@
         "channels = (int) [ 1, MAX ], "
         "rate = (int) [ 1,  MAX ], "
         "endianness = (int) BYTE_ORDER, "
-        "width = (int) 16, " "depth = (int) 16, " "signed = (bool) TRUE")
+        "width = (int) {16, 24, 32}, " "depth = (int) {16, 24, 32}, " "signed = (bool) TRUE")
     );
 
 static GstStaticPadTemplate volume_src_template = GST_STATIC_PAD_TEMPLATE
@@ -119,7 +127,7 @@
         "channels = (int) [ 1, MAX ], "
         "rate = (int) [ 1,  MAX ], "
         "endianness = (int) BYTE_ORDER, "
-        "width = (int) 16, " "depth = (int) 16, " "signed = (bool) TRUE")
+        "width = (int) {16, 24, 32}, " "depth = (int) {16, 24, 32}, " "signed = (bool) TRUE")
     );
 
 static void gst_volume_interface_init (GstImplementsInterfaceClass * klass);
@@ -162,6 +170,14 @@
     guint n_bytes);
 static void volume_process_float (GstVolume * this, gpointer bytes,
     guint n_bytes);
+static void volume_process_int32 (GstVolume * this, gpointer bytes,
+    guint n_bytes);
+static void volume_process_int32_clamp (GstVolume * this, gpointer bytes,
+    guint n_bytes);
+static void volume_process_int24 (GstVolume * this, gpointer bytes,
+    guint n_bytes);
+static void volume_process_int24_clamp (GstVolume * this, gpointer bytes,
+    guint n_bytes);
 static void volume_process_int16 (GstVolume * this, gpointer bytes,
     guint n_bytes);
 static void volume_process_int16_clamp (GstVolume * this, gpointer bytes,
@@ -175,14 +191,36 @@
   this->process = NULL;
   switch (this->format) {
     case GST_VOLUME_FORMAT_INT:
-      /* FIXME: should we also support gint8, gint32? */
-      /* only clamp if the gain is greater than 1.0
-       * FIXME: real_vol_i can change while processing the buffer!
-       */
-      if (this->real_vol_i > VOLUME_UNITY_INT16)
-        this->process = volume_process_int16_clamp;
-      else
-        this->process = volume_process_int16;
+      switch (this->width) {
+        /* FIXME: should we also support gint8? */
+        case 32:
+          /* only clamp if the gain is greater than 1.0
+           * FIXME: real_vol_i can change while processing the buffer!
+           */
+          if (this->real_vol_i32 > VOLUME_UNITY_INT32)
+            this->process = volume_process_int32_clamp;
+          else
+            this->process = volume_process_int32;
+          break;
+        case 24:
+          /* only clamp if the gain is greater than 1.0
+           * FIXME: real_vol_i can change while processing the buffer!
+           */
+          if (this->real_vol_i24 > VOLUME_UNITY_INT24)
+            this->process = volume_process_int24_clamp;
+          else
+            this->process = volume_process_int24;
+          break;
+        case 16:
+          /* only clamp if the gain is greater than 1.0
+           * FIXME: real_vol_i can change while processing the buffer!
+           */
+          if (this->real_vol_i16 > VOLUME_UNITY_INT16)
+            this->process = volume_process_int16_clamp;
+          else
+            this->process = volume_process_int16;
+          break;
+      }
       break;
     case GST_VOLUME_FORMAT_FLOAT:
       switch (this->width) {
@@ -206,11 +244,13 @@
 
   if (this->mute) {
     this->real_vol_f = 0.0;
-    this->real_vol_i = 0;
+    this->real_vol_i16 = this->real_vol_i24 = this->real_vol_i32 = 0;
   } else {
     this->real_vol_f = this->volume_f;
-    this->real_vol_i = this->volume_i;
-    passthrough = (this->volume_i == VOLUME_UNITY_INT16);
+    this->real_vol_i16 = this->volume_i16;
+    this->real_vol_i24 = this->volume_i24;
+    this->real_vol_i32 = this->volume_i32;
+    passthrough = (this->volume_i16 == VOLUME_UNITY_INT16);
   }
   volume_choose_func (this);
   gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (this), passthrough);
@@ -251,7 +291,9 @@
   g_return_if_fail (GST_IS_VOLUME (this));
 
   this->volume_f = (gfloat) volumes[0] / VOLUME_STEPS;
-  this->volume_i = this->volume_f * VOLUME_UNITY_INT16;
+  this->volume_i32 = this->volume_f * VOLUME_UNITY_INT32;
+  this->volume_i24 = this->volume_f * VOLUME_UNITY_INT24;
+  this->volume_i16 = this->volume_f * VOLUME_UNITY_INT16;
 
   volume_update_real_volume (this);
 }
@@ -355,10 +397,10 @@
   GstMixerTrack *track = NULL;
 
   this->mute = FALSE;
-  this->volume_i = VOLUME_UNITY_INT16;
-  this->volume_f = 1.0;
-  this->real_vol_i = VOLUME_UNITY_INT16;
-  this->real_vol_f = 1.0;
+  this->volume_i16 = this->real_vol_i16 = VOLUME_UNITY_INT16;
+  this->volume_i24 = this->real_vol_i24 = VOLUME_UNITY_INT24;
+  this->volume_i32 = this->real_vol_i32 = VOLUME_UNITY_INT32;
+  this->volume_f = this->real_vol_f = 1.0;
   this->tracklist = NULL;
   this->format = GST_VOLUME_FORMAT_NONE;
 
@@ -409,6 +451,91 @@
 }
 
 static void
+volume_process_int32 (GstVolume * this, gpointer bytes, guint n_bytes)
+{
+  gint *data = (gint *) bytes;
+  guint i, num_samples;
+  gint64 val;
+
+  num_samples = n_bytes / sizeof (gint);
+  for (i = 0; i < num_samples; i++) {
+    /* we use bitshifting instead of dividing by UNITY_INT for speed */
+    val = (gint64) * data;
+    val =
+        (((gint64) this->real_vol_i32 * val) >> VOLUME_UNITY_INT32_BIT_SHIFT);
+    *data++ = (gint) val;
+  }
+}
+
+static void
+volume_process_int32_clamp (GstVolume * this, gpointer bytes, guint n_bytes)
+{
+  gint *data = (gint *) bytes;
+  guint i, num_samples;
+  gint64 val;
+
+  num_samples = n_bytes / sizeof (gint);
+
+  for (i = 0; i < num_samples; i++) {
+    /* we use bitshifting instead of dividing by UNITY_INT for speed */
+    val = (gint64) * data;
+    val =
+        (((gint64) this->real_vol_i32 * val) >> VOLUME_UNITY_INT32_BIT_SHIFT);
+    *data++ = (gint) CLAMP (val, VOLUME_MIN_INT32, VOLUME_MAX_INT32);
+  }
+}
+
+#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
+#define get_unaligned_i24(_x) ( (((guint8*)_x)[0]) | ((((guint8*)_x)[1]) << 8) | ((((gint8*)_x)[2]) << 16) )
+#define write_unaligned_u24(_x,samp) do { *(_x)++ = samp & 0xFF; *(_x)++ = (samp >> 8) & 0xFF; *(_x)++ = (samp >> 16) & 0xFF; } while (0)
+#else /* BIG ENDIAN */
+#define get_unaligned_i24(_x) ( (((guint8*)_x)[2]) | ((((guint8*)_x)[1]) << 8) | ((((gint8*)_x)[0]) << 16) )
+#define write_unaligned_u24(_x,samp) do { *(_x)++ = (samp >> 16) & 0xFF; *(_x)++ = (samp >> 8) & 0xFF; *(_x)++ = samp & 0xFF; } while (0)
+#endif
+
+static void
+volume_process_int24 (GstVolume * this, gpointer bytes, guint n_bytes)
+{
+  gint8 *data = (gint8 *) bytes; /* treat the data as a byte stream */
+  guint i, num_samples;
+  guint32 samp;
+  gint64 val;
+
+  num_samples = n_bytes / (sizeof (gint8) * 3);
+  for (i = 0; i < num_samples; i++) {
+    samp = get_unaligned_i24 (data);
+
+    val = (gint32) samp;
+    val = (((gint64) this->real_vol_i24 * val) >> VOLUME_UNITY_INT24_BIT_SHIFT);
+    samp = (guint32) val;
+
+    /* write the value back into the stream */
+    write_unaligned_u24 (data, samp);
+  }
+}
+
+static void
+volume_process_int24_clamp (GstVolume * this, gpointer bytes, guint n_bytes)
+{
+  gint8 *data = (gint8 *) bytes; /* treat the data as a byte stream */
+  guint i, num_samples;
+  guint32 samp;
+  gint64 val;
+
+  num_samples = n_bytes / (sizeof (gint8) * 3);
+  for (i = 0; i < num_samples; i++) {
+    samp = get_unaligned_i24 (data);
+
+    val = (gint32) samp;
+    val = (((gint64) this->real_vol_i24 * val) >> VOLUME_UNITY_INT24_BIT_SHIFT);
+    samp = (guint32) CLAMP (val, VOLUME_MIN_INT24, VOLUME_MAX_INT24);
+
+    /* write the value back into the stream */
+    write_unaligned_u24 (data, samp);
+  }
+}
+
+static void
 volume_process_int16 (GstVolume * this, gpointer bytes, guint n_bytes)
 {
   gint16 *data = (gint16 *) bytes;
@@ -425,7 +552,7 @@
     /* we use bitshifting instead of dividing by UNITY_INT for speed */
     val = (gint) * data;
     *data++ =
-        (gint16) ((this->real_vol_i * val) >> VOLUME_UNITY_INT16_BIT_SHIFT);
+        (gint16) ((this->real_vol_i16 * val) >> VOLUME_UNITY_INT16_BIT_SHIFT);
   }
 }
 
@@ -446,7 +573,7 @@
     /* we use bitshifting instead of dividing by UNITY_INT for speed */
     val = (gint) * data;
     *data++ =
-        (gint16) CLAMP ((this->real_vol_i *
+        (gint16) CLAMP ((this->real_vol_i16 *
             val) >> VOLUME_UNITY_INT16_BIT_SHIFT, VOLUME_MIN_INT16,
         VOLUME_MAX_INT16);
   }
@@ -549,8 +676,10 @@
   g_return_if_fail (GST_IS_VOLUME (this));
 
   this->volume_f = g_value_get_double (value);
-  this->volume_i = this->volume_f * VOLUME_UNITY_INT16;
-
+  this->volume_i16 = this->volume_f * VOLUME_UNITY_INT16;
+  this->volume_i24 = this->volume_f * VOLUME_UNITY_INT24;
+  this->volume_i32 = this->volume_f * VOLUME_UNITY_INT32;
+  
   volume_update_real_volume (this);
 }
 
@@ -595,7 +724,7 @@
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
-  /*oil_init (); */
+  oil_init ();
 
   /* initialize gst controller library */
   gst_controller_init (NULL, NULL);
--- ../../../gst-plugins-base-0.10.13/gst/volume/gstvolume.h	2007-02-28 23:42:18.000000000 +0900
+++ gstvolume.h	2007-06-08 20:15:42.000000000 +0800
@@ -59,7 +59,9 @@
   void (*process)(GstVolume*, gpointer, guint);
 
   gboolean mute;
-  gint   volume_i, real_vol_i; /* the _i(nt) values get synchronized with the */
+  gint   volume_i32, real_vol_i32;
+  gint   volume_i24, real_vol_i24; /* the _i(nt) values get synchronized with the */
+  gint   volume_i16, real_vol_i16; /* the _i(nt) values get synchronized with the */
   gfloat volume_f, real_vol_f; /* _f(loat) values on each update */
   
   GList *tracklist;
