]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/sample-util.c
Fix up according to Coding Style
[pulseaudio] / src / pulsecore / sample-util.c
index b42b79d19a9b8030d327dc1e69c243ffda06a474..ee1da60aec3301db4fa3bda9eb072c0070ea152f 100644 (file)
@@ -6,7 +6,7 @@
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
-  by the Free Software Foundation; either version 2 of the License,
+  by the Free Software Foundation; either version 2.1 of the License,
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
 
 
-#include <liboil/liboilfuncs.h>
-#include <liboil/liboil.h>
+#include <pulse/timeval.h>
 
 #include <pulsecore/log.h>
 
 #include <pulsecore/log.h>
+#include <pulsecore/core-error.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/g711.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/g711.h>
+#include <pulsecore/core-util.h>
 
 #include "sample-util.h"
 #include "endianmacros.h"
 
 #include "sample-util.h"
 #include "endianmacros.h"
@@ -77,6 +80,10 @@ static uint8_t silence_byte(pa_sample_format_t format) {
         case PA_SAMPLE_S32BE:
         case PA_SAMPLE_FLOAT32LE:
         case PA_SAMPLE_FLOAT32BE:
         case PA_SAMPLE_S32BE:
         case PA_SAMPLE_FLOAT32LE:
         case PA_SAMPLE_FLOAT32BE:
+        case PA_SAMPLE_S24LE:
+        case PA_SAMPLE_S24BE:
+        case PA_SAMPLE_S24_32LE:
+        case PA_SAMPLE_S24_32BE:
             return 0;
         case PA_SAMPLE_ALAW:
             return 0xd5;
             return 0;
         case PA_SAMPLE_ALAW:
             return 0xd5;
@@ -85,7 +92,6 @@ static uint8_t silence_byte(pa_sample_format_t format) {
         default:
             pa_assert_not_reached();
     }
         default:
             pa_assert_not_reached();
     }
-    return 0;
 }
 
 void* pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
 }
 
 void* pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
@@ -97,56 +103,74 @@ void* pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
     return p;
 }
 
     return p;
 }
 
-static void calc_linear_integer_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_sample_spec *spec) {
-    unsigned k;
+#define VOLUME_PADDING 32
 
 
-    pa_assert(streams);
-    pa_assert(spec);
+static void calc_linear_integer_volume(int32_t linear[], const pa_cvolume *volume) {
+    unsigned channel, nchannels, padding;
 
 
-    for (k = 0; k < nstreams; k++) {
-        unsigned channel;
+    pa_assert(linear);
+    pa_assert(volume);
 
 
-        for (channel = 0; channel < spec->channels; channel++) {
-            pa_mix_info *m = streams + k;
-            m->linear[channel].i = (int32_t) (pa_sw_volume_to_linear(m->volume.values[channel]) * 0x10000);
-        }
-    }
+    nchannels = volume->channels;
+
+    for (channel = 0; channel < nchannels; channel++)
+        linear[channel] = (int32_t) lrint(pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
+
+    for (padding = 0; padding < VOLUME_PADDING; padding++, channel++)
+        linear[channel] = linear[padding];
 }
 
 }
 
-static void calc_linear_integer_volume(int32_t linear[], const pa_cvolume *volume) {
-    unsigned channel;
+static void calc_linear_float_volume(float linear[], const pa_cvolume *volume) {
+    unsigned channel, nchannels, padding;
 
     pa_assert(linear);
     pa_assert(volume);
 
 
     pa_assert(linear);
     pa_assert(volume);
 
-    for (channel = 0; channel < volume->channels; channel++)
-        linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
+    nchannels = volume->channels;
+
+    for (channel = 0; channel < nchannels; channel++)
+        linear[channel] = (float) pa_sw_volume_to_linear(volume->values[channel]);
+
+    for (padding = 0; padding < VOLUME_PADDING; padding++, channel++)
+        linear[channel] = linear[padding];
 }
 
 }
 
-static void calc_linear_float_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_sample_spec *spec) {
-    unsigned k;
+static void calc_linear_integer_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) {
+    unsigned k, channel;
+    float linear[PA_CHANNELS_MAX + VOLUME_PADDING];
 
     pa_assert(streams);
     pa_assert(spec);
 
     pa_assert(streams);
     pa_assert(spec);
+    pa_assert(volume);
+
+    calc_linear_float_volume(linear, volume);
 
     for (k = 0; k < nstreams; k++) {
 
     for (k = 0; k < nstreams; k++) {
-        unsigned channel;
 
         for (channel = 0; channel < spec->channels; channel++) {
             pa_mix_info *m = streams + k;
 
         for (channel = 0; channel < spec->channels; channel++) {
             pa_mix_info *m = streams + k;
-            m->linear[channel].f = pa_sw_volume_to_linear(m->volume.values[channel]);
+            m->linear[channel].i = (int32_t) lrint(pa_sw_volume_to_linear(m->volume.values[channel]) * linear[channel] * 0x10000);
         }
     }
 }
 
         }
     }
 }
 
-static void calc_linear_float_volume(float linear[], const pa_cvolume *volume) {
-    unsigned channel;
+static void calc_linear_float_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) {
+    unsigned k, channel;
+    float linear[PA_CHANNELS_MAX + VOLUME_PADDING];
 
 
-    pa_assert(linear);
+    pa_assert(streams);
+    pa_assert(spec);
     pa_assert(volume);
 
     pa_assert(volume);
 
-    for (channel = 0; channel < volume->channels; channel++)
-        linear[channel] = pa_sw_volume_to_linear(volume->values[channel]);
+    calc_linear_float_volume(linear, volume);
+
+    for (k = 0; k < nstreams; k++) {
+
+        for (channel = 0; channel < spec->channels; channel++) {
+            pa_mix_info *m = streams + k;
+            m->linear[channel].f = (float) (pa_sw_volume_to_linear(m->volume.values[channel]) * linear[channel]);
+        }
+    }
 }
 
 size_t pa_mix(
 }
 
 size_t pa_mix(
@@ -160,7 +184,8 @@ size_t pa_mix(
 
     pa_cvolume full_volume;
     unsigned k;
 
     pa_cvolume full_volume;
     unsigned k;
-    size_t d = 0;
+    unsigned z;
+    void *end;
 
     pa_assert(streams);
     pa_assert(data);
 
     pa_assert(streams);
     pa_assert(data);
@@ -170,45 +195,55 @@ size_t pa_mix(
     if (!volume)
         volume = pa_cvolume_reset(&full_volume, spec->channels);
 
     if (!volume)
         volume = pa_cvolume_reset(&full_volume, spec->channels);
 
+    if (mute || pa_cvolume_is_muted(volume) || nstreams <= 0) {
+        pa_silence_memory(data, length, spec);
+        return length;
+    }
+
     for (k = 0; k < nstreams; k++)
         streams[k].ptr = (uint8_t*) pa_memblock_acquire(streams[k].chunk.memblock) + streams[k].chunk.index;
 
     for (k = 0; k < nstreams; k++)
         streams[k].ptr = (uint8_t*) pa_memblock_acquire(streams[k].chunk.memblock) + streams[k].chunk.index;
 
+    for (z = 0; z < nstreams; z++)
+        if (length > streams[z].chunk.length)
+            length = streams[z].chunk.length;
+
+    end = (uint8_t*) data + length;
+
     switch (spec->format) {
 
         case PA_SAMPLE_S16NE:{
             unsigned channel = 0;
     switch (spec->format) {
 
         case PA_SAMPLE_S16NE:{
             unsigned channel = 0;
-            int32_t linear[PA_CHANNELS_MAX];
 
 
-            calc_linear_integer_stream_volumes(streams, nstreams, spec);
-            calc_linear_integer_volume(linear, volume);
+            calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
 
 
-            for (d = 0;; d += sizeof(int16_t)) {
+            while (data < end) {
                 int32_t sum = 0;
                 unsigned i;
 
                 int32_t sum = 0;
                 unsigned i;
 
-                if (PA_UNLIKELY(d >= length))
-                    goto finish;
-
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
-                    int32_t v, cv = m->linear[channel].i;
+                    int32_t v, lo, hi, cv = m->linear[channel].i;
 
 
-                    if (PA_UNLIKELY(d >= m->chunk.length))
-                        goto finish;
+                    if (PA_UNLIKELY(cv <= 0))
+                        continue;
 
 
-                    if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0))
-                        v = 0;
-                    else {
-                        v = *((int16_t*) m->ptr);
-                        v = (v * cv) / 0x10000;
-                    }
+                    /* Multiplying the 32bit volume factor with the
+                     * 16bit sample might result in an 48bit value. We
+                     * want to do without 64 bit integers and hence do
+                     * the multiplication independantly for the HI and
+                     * LO part of the volume. */
 
 
+                    hi = cv >> 16;
+                    lo = cv & 0xFFFF;
+
+                    v = *((int16_t*) m->ptr);
+                    v = ((v * lo) >> 16) + (v * hi);
                     sum += v;
                     sum += v;
+
                     m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
                 }
 
                 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
                     m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
                 }
 
                 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
-                sum = (sum * linear[channel]) / 0x10000;
                 *((int16_t*) data) = (int16_t) sum;
 
                 data = (uint8_t*) data + sizeof(int16_t);
                 *((int16_t*) data) = (int16_t) sum;
 
                 data = (uint8_t*) data + sizeof(int16_t);
@@ -222,38 +257,31 @@ size_t pa_mix(
 
         case PA_SAMPLE_S16RE:{
             unsigned channel = 0;
 
         case PA_SAMPLE_S16RE:{
             unsigned channel = 0;
-            int32_t linear[PA_CHANNELS_MAX];
 
 
-            calc_linear_integer_stream_volumes(streams, nstreams, spec);
-            calc_linear_integer_volume(linear, volume);
+            calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
 
 
-            for (d = 0;; d += sizeof(int16_t)) {
+            while (data < end) {
                 int32_t sum = 0;
                 unsigned i;
 
                 int32_t sum = 0;
                 unsigned i;
 
-                if (PA_UNLIKELY(d >= length))
-                    goto finish;
-
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
-                    int32_t v, cv = m->linear[channel].i;
+                    int32_t v, lo, hi, cv = m->linear[channel].i;
 
 
-                    if (PA_UNLIKELY(d >= m->chunk.length))
-                        goto finish;
+                    if (PA_UNLIKELY(cv <= 0))
+                        continue;
 
 
-                    if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0))
-                        v = 0;
-                    else {
-                        v = PA_INT16_SWAP(*((int16_t*) m->ptr));
-                        v = (v * cv) / 0x10000;
-                    }
+                    hi = cv >> 16;
+                    lo = cv & 0xFFFF;
 
 
+                    v = PA_INT16_SWAP(*((int16_t*) m->ptr));
+                    v = ((v * lo) >> 16) + (v * hi);
                     sum += v;
                     sum += v;
+
                     m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
                 }
 
                 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
                     m->ptr = (uint8_t*) m->ptr + sizeof(int16_t);
                 }
 
                 sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
-                sum = (sum * linear[channel]) / 0x10000;
                 *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum);
 
                 data = (uint8_t*) data + sizeof(int16_t);
                 *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum);
 
                 data = (uint8_t*) data + sizeof(int16_t);
@@ -267,39 +295,29 @@ size_t pa_mix(
 
         case PA_SAMPLE_S32NE:{
             unsigned channel = 0;
 
         case PA_SAMPLE_S32NE:{
             unsigned channel = 0;
-            int32_t linear[PA_CHANNELS_MAX];
 
 
-            calc_linear_integer_stream_volumes(streams, nstreams, spec);
-            calc_linear_integer_volume(linear, volume);
+            calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
 
 
-            for (d = 0;; d += sizeof(int32_t)) {
+            while (data < end) {
                 int64_t sum = 0;
                 unsigned i;
 
                 int64_t sum = 0;
                 unsigned i;
 
-                if (PA_UNLIKELY(d >= length))
-                    goto finish;
-
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
-                    int64_t v;
                     int32_t cv = m->linear[channel].i;
                     int32_t cv = m->linear[channel].i;
+                    int64_t v;
 
 
-                    if (PA_UNLIKELY(d >= m->chunk.length))
-                        goto finish;
-
-                    if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0))
-                        v = 0;
-                    else {
-                        v = *((int32_t*) m->ptr);
-                        v = (v * cv) / 0x10000;
-                    }
+                    if (PA_UNLIKELY(cv <= 0))
+                        continue;
 
 
+                    v = *((int32_t*) m->ptr);
+                    v = (v * cv) >> 16;
                     sum += v;
                     sum += v;
+
                     m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
                 }
 
                 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
                     m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
                 }
 
                 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
-                sum = (sum * linear[channel]) / 0x10000;
                 *((int32_t*) data) = (int32_t) sum;
 
                 data = (uint8_t*) data + sizeof(int32_t);
                 *((int32_t*) data) = (int32_t) sum;
 
                 data = (uint8_t*) data + sizeof(int32_t);
@@ -313,39 +331,29 @@ size_t pa_mix(
 
         case PA_SAMPLE_S32RE:{
             unsigned channel = 0;
 
         case PA_SAMPLE_S32RE:{
             unsigned channel = 0;
-            int32_t linear[PA_CHANNELS_MAX];
 
 
-            calc_linear_integer_stream_volumes(streams, nstreams, spec);
-            calc_linear_integer_volume(linear, volume);
+            calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
 
 
-            for (d = 0;; d += sizeof(int32_t)) {
+            while (data < end) {
                 int64_t sum = 0;
                 unsigned i;
 
                 int64_t sum = 0;
                 unsigned i;
 
-                if (PA_UNLIKELY(d >= length))
-                    goto finish;
-
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
-                    int64_t v;
                     int32_t cv = m->linear[channel].i;
                     int32_t cv = m->linear[channel].i;
+                    int64_t v;
 
 
-                    if (PA_UNLIKELY(d >= m->chunk.length))
-                        goto finish;
-
-                    if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0))
-                        v = 0;
-                    else {
-                        v = PA_INT32_SWAP(*((int32_t*) m->ptr));
-                        v = (v * cv) / 0x10000;
-                    }
+                    if (PA_UNLIKELY(cv <= 0))
+                        continue;
 
 
+                    v = PA_INT32_SWAP(*((int32_t*) m->ptr));
+                    v = (v * cv) >> 16;
                     sum += v;
                     sum += v;
+
                     m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
                 }
 
                 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
                     m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
                 }
 
                 sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
-                sum = (sum * linear[channel]) / 0x10000;
                 *((int32_t*) data) = PA_INT32_SWAP((int32_t) sum);
 
                 data = (uint8_t*) data + sizeof(int32_t);
                 *((int32_t*) data) = PA_INT32_SWAP((int32_t) sum);
 
                 data = (uint8_t*) data + sizeof(int32_t);
@@ -357,43 +365,34 @@ size_t pa_mix(
             break;
         }
 
             break;
         }
 
-        case PA_SAMPLE_U8: {
+        case PA_SAMPLE_S24NE: {
             unsigned channel = 0;
             unsigned channel = 0;
-            int32_t linear[PA_CHANNELS_MAX];
 
 
-            calc_linear_integer_stream_volumes(streams, nstreams, spec);
-            calc_linear_integer_volume(linear, volume);
+            calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
 
 
-            for (d = 0;; d ++) {
-                int32_t sum = 0;
+            while (data < end) {
+                int64_t sum = 0;
                 unsigned i;
 
                 unsigned i;
 
-                if (PA_UNLIKELY(d >= length))
-                    goto finish;
-
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
-                    int32_t v, cv = m->linear[channel].i;
-
-                    if (PA_UNLIKELY(d >= m->chunk.length))
-                        goto finish;
+                    int32_t cv = m->linear[channel].i;
+                    int64_t v;
 
 
-                    if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0))
-                        v = 0;
-                    else {
-                        v = (int32_t) *((uint8_t*) m->ptr) - 0x80;
-                        v = (v * cv) / 0x10000;
-                    }
+                    if (PA_UNLIKELY(cv <= 0))
+                        continue;
 
 
+                    v = (int32_t) (PA_READ24NE(m->ptr) << 8);
+                    v = (v * cv) >> 16;
                     sum += v;
                     sum += v;
-                    m->ptr = (uint8_t*) m->ptr + 1;
+
+                    m->ptr = (uint8_t*) m->ptr + 3;
                 }
 
                 }
 
-                sum = (sum * linear[channel]) / 0x10000;
-                sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F);
-                *((uint8_t*) data) = (uint8_t) (sum + 0x80);
+                sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
+                PA_WRITE24NE(data, ((uint32_t) sum) >> 8);
 
 
-                data = (uint8_t*) data + 1;
+                data = (uint8_t*) data + 3;
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
@@ -402,43 +401,34 @@ size_t pa_mix(
             break;
         }
 
             break;
         }
 
-        case PA_SAMPLE_ULAW: {
+        case PA_SAMPLE_S24RE: {
             unsigned channel = 0;
             unsigned channel = 0;
-            int32_t linear[PA_CHANNELS_MAX];
 
 
-            calc_linear_integer_stream_volumes(streams, nstreams, spec);
-            calc_linear_integer_volume(linear, volume);
+            calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
 
 
-            for (d = 0;; d ++) {
-                int32_t sum = 0;
+            while (data < end) {
+                int64_t sum = 0;
                 unsigned i;
 
                 unsigned i;
 
-                if (PA_UNLIKELY(d >= length))
-                    goto finish;
-
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
-                    int32_t v, cv = m->linear[channel].i;
-
-                    if (PA_UNLIKELY(d >= m->chunk.length))
-                        goto finish;
+                    int32_t cv = m->linear[channel].i;
+                    int64_t v;
 
 
-                    if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0))
-                        v = 0;
-                    else {
-                        v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr));
-                        v = (v * cv) / 0x10000;
-                    }
+                    if (PA_UNLIKELY(cv <= 0))
+                        continue;
 
 
+                    v = (int32_t) (PA_READ24RE(m->ptr) << 8);
+                    v = (v * cv) >> 16;
                     sum += v;
                     sum += v;
-                    m->ptr = (uint8_t*) m->ptr + 1;
+
+                    m->ptr = (uint8_t*) m->ptr + 3;
                 }
 
                 }
 
-                sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
-                sum = (sum * linear[channel]) / 0x10000;
-                *((uint8_t*) data) = (uint8_t) st_14linear2ulaw(sum >> 2);
+                sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
+                PA_WRITE24RE(data, ((uint32_t) sum) >> 8);
 
 
-                data = (uint8_t*) data + 1;
+                data = (uint8_t*) data + 3;
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
@@ -447,43 +437,34 @@ size_t pa_mix(
             break;
         }
 
             break;
         }
 
-        case PA_SAMPLE_ALAW: {
+        case PA_SAMPLE_S24_32NE: {
             unsigned channel = 0;
             unsigned channel = 0;
-            int32_t linear[PA_CHANNELS_MAX];
 
 
-            calc_linear_integer_stream_volumes(streams, nstreams, spec);
-            calc_linear_integer_volume(linear, volume);
+            calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
 
 
-            for (d = 0;; d ++) {
-                int32_t sum = 0;
+            while (data < end) {
+                int64_t sum = 0;
                 unsigned i;
 
                 unsigned i;
 
-                if (PA_UNLIKELY(d >= length))
-                    goto finish;
-
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
-                    int32_t v, cv = m->linear[channel].i;
-
-                    if (PA_UNLIKELY(d >= m->chunk.length))
-                        goto finish;
+                    int32_t cv = m->linear[channel].i;
+                    int64_t v;
 
 
-                    if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0))
-                        v = 0;
-                    else {
-                        v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr));
-                        v = (v * cv) / 0x10000;
-                    }
+                    if (PA_UNLIKELY(cv <= 0))
+                        continue;
 
 
+                    v = (int32_t) (*((uint32_t*)m->ptr) << 8);
+                    v = (v * cv) >> 16;
                     sum += v;
                     sum += v;
-                    m->ptr = (uint8_t*) m->ptr + 1;
+
+                    m->ptr = (uint8_t*) m->ptr + sizeof(int32_t);
                 }
 
                 }
 
-                sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
-                sum = (sum * linear[channel]) / 0x10000;
-                *((uint8_t*) data) = (uint8_t) st_13linear2alaw(sum >> 3);
+                sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
+                *((uint32_t*) data) = ((uint32_t) (int32_t) sum) >> 8;
 
 
-                data = (uint8_t*) data + 1;
+                data = (uint8_t*) data + sizeof(uint32_t);
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
@@ -492,42 +473,34 @@ size_t pa_mix(
             break;
         }
 
             break;
         }
 
-        case PA_SAMPLE_FLOAT32NE: {
+        case PA_SAMPLE_S24_32RE: {
             unsigned channel = 0;
             unsigned channel = 0;
-            float linear[PA_CHANNELS_MAX];
 
 
-            calc_linear_float_stream_volumes(streams, nstreams, spec);
-            calc_linear_float_volume(linear, volume);
+            calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
 
 
-            for (d = 0;; d += sizeof(float)) {
-                float sum = 0;
+            while (data < end) {
+                int64_t sum = 0;
                 unsigned i;
 
                 unsigned i;
 
-                if (PA_UNLIKELY(d >= length))
-                    goto finish;
-
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
-                    float v, cv = m->linear[channel].f;
-
-                    if (PA_UNLIKELY(d >= m->chunk.length))
-                        goto finish;
+                    int32_t cv = m->linear[channel].i;
+                    int64_t v;
 
 
-                    if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0))
-                        v = 0;
-                    else {
-                        v = *((float*) m->ptr);
-                        v *= cv;
-                    }
+                    if (PA_UNLIKELY(cv <= 0))
+                        continue;
 
 
+                    v = (int32_t) (PA_UINT32_SWAP(*((uint32_t*) m->ptr)) << 8);
+                    v = (v * cv) >> 16;
                     sum += v;
                     sum += v;
-                    m->ptr = (uint8_t*) m->ptr + sizeof(float);
+
+                    m->ptr = (uint8_t*) m->ptr + 3;
                 }
 
                 }
 
-                sum *= linear[channel];
-                *((float*) data) = sum;
+                sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL);
+                *((uint32_t*) data) = PA_INT32_SWAP(((uint32_t) (int32_t) sum) >> 8);
 
 
-                data = (uint8_t*) data + sizeof(float);
+                data = (uint8_t*) data + sizeof(uint32_t);
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
@@ -536,44 +509,33 @@ size_t pa_mix(
             break;
         }
 
             break;
         }
 
-        case PA_SAMPLE_FLOAT32RE: {
+        case PA_SAMPLE_U8: {
             unsigned channel = 0;
             unsigned channel = 0;
-            float linear[PA_CHANNELS_MAX];
 
 
-            calc_linear_float_stream_volumes(streams, nstreams, spec);
-            calc_linear_float_volume(linear, volume);
+            calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
 
 
-            for (d = 0;; d += sizeof(float)) {
-                float sum = 0;
+            while (data < end) {
+                int32_t sum = 0;
                 unsigned i;
 
                 unsigned i;
 
-                if (PA_UNLIKELY(d >= length))
-                    goto finish;
-
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
                 for (i = 0; i < nstreams; i++) {
                     pa_mix_info *m = streams + i;
-                    float v, cv = m->linear[channel].f;
-
-                    if (PA_UNLIKELY(d >= m->chunk.length))
-                        goto finish;
+                    int32_t v, cv = m->linear[channel].i;
 
 
-                    if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0))
-                        v = 0;
-                    else {
-                        uint32_t z = *(uint32_t*) m->ptr;
-                        z = PA_UINT32_SWAP(z);
-                        v = *((float*) &z);
-                        v *= cv;
-                    }
+                    if (PA_UNLIKELY(cv <= 0))
+                        continue;
 
 
+                    v = (int32_t) *((uint8_t*) m->ptr) - 0x80;
+                    v = (v * cv) >> 16;
                     sum += v;
                     sum += v;
-                    m->ptr = (uint8_t*) m->ptr + sizeof(float);
+
+                    m->ptr = (uint8_t*) m->ptr + 1;
                 }
 
                 }
 
-                sum *= linear[channel];
-                *((uint32_t*) data) = PA_UINT32_SWAP(*(uint32_t*) &sum);
+                sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F);
+                *((uint8_t*) data) = (uint8_t) (sum + 0x80);
 
 
-                data = (uint8_t*) data + sizeof(float);
+                data = (uint8_t*) data + 1;
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
@@ -582,256 +544,222 @@ size_t pa_mix(
             break;
         }
 
             break;
         }
 
-        default:
-            pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format));
-            pa_assert_not_reached();
-    }
-
-finish:
-
-    for (k = 0; k < nstreams; k++)
-        pa_memblock_release(streams[k].chunk.memblock);
-
-    return d;
-}
-
-
-void pa_volume_memchunk(
-        pa_memchunk*c,
-        const pa_sample_spec *spec,
-        const pa_cvolume *volume) {
-
-    void *ptr;
+        case PA_SAMPLE_ULAW: {
+            unsigned channel = 0;
 
 
-    pa_assert(c);
-    pa_assert(spec);
-    pa_assert(c->length % pa_frame_size(spec) == 0);
-    pa_assert(volume);
+            calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
 
 
-    if (pa_memblock_is_silence(c->memblock))
-        return;
+            while (data < end) {
+                int32_t sum = 0;
+                unsigned i;
 
 
-    if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
-        return;
+                for (i = 0; i < nstreams; i++) {
+                    pa_mix_info *m = streams + i;
+                    int32_t v, hi, lo, cv = m->linear[channel].i;
 
 
-    if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
-        pa_silence_memchunk(c, spec);
-        return;
-    }
+                    if (PA_UNLIKELY(cv <= 0))
+                        continue;
 
 
-    ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index;
+                    hi = cv >> 16;
+                    lo = cv & 0xFFFF;
 
 
-    switch (spec->format) {
-
-        case PA_SAMPLE_S16NE: {
-            int16_t *d;
-            size_t n;
-            unsigned channel;
-            int32_t linear[PA_CHANNELS_MAX];
+                    v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr));
+                    v = ((v * lo) >> 16) + (v * hi);
+                    sum += v;
 
 
-            calc_linear_integer_volume(linear, volume);
+                    m->ptr = (uint8_t*) m->ptr + 1;
+                }
 
 
-            for (channel = 0, d = ptr, n = c->length/sizeof(int16_t); n > 0; d++, n--) {
-                int32_t t;
+                sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
+                *((uint8_t*) data) = (uint8_t) st_14linear2ulaw((int16_t) sum >> 2);
 
 
-                t = (int32_t)(*d);
-                t = (t * linear[channel]) / 0x10000;
-                t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
-                *d = (int16_t) t;
+                data = (uint8_t*) data + 1;
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
             }
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
             }
+
             break;
         }
 
             break;
         }
 
-        case PA_SAMPLE_S16RE: {
-            int16_t *d;
-            size_t n;
-            unsigned channel;
-            int32_t linear[PA_CHANNELS_MAX];
+        case PA_SAMPLE_ALAW: {
+            unsigned channel = 0;
 
 
-            calc_linear_integer_volume(linear, volume);
+            calc_linear_integer_stream_volumes(streams, nstreams, volume, spec);
 
 
-            for (channel = 0, d = ptr, n = c->length/sizeof(int16_t); n > 0; d++, n--) {
-                int32_t t;
+            while (data < end) {
+                int32_t sum = 0;
+                unsigned i;
 
 
-                t = (int32_t)(PA_INT16_SWAP(*d));
-                t = (t * linear[channel]) / 0x10000;
-                t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
-                *d = PA_INT16_SWAP((int16_t) t);
+                for (i = 0; i < nstreams; i++) {
+                    pa_mix_info *m = streams + i;
+                    int32_t v, hi, lo, cv = m->linear[channel].i;
 
 
-                if (PA_UNLIKELY(++channel >= spec->channels))
-                    channel = 0;
-            }
+                    if (PA_UNLIKELY(cv <= 0))
+                        continue;
 
 
-            break;
-        }
+                    hi = cv >> 16;
+                    lo = cv & 0xFFFF;
 
 
-        case PA_SAMPLE_S32NE: {
-            int32_t *d;
-            size_t n;
-            unsigned channel;
-            int32_t linear[PA_CHANNELS_MAX];
+                    v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr));
+                    v = ((v * lo) >> 16) + (v * hi);
+                    sum += v;
 
 
-            calc_linear_integer_volume(linear, volume);
+                    m->ptr = (uint8_t*) m->ptr + 1;
+                }
 
 
-            for (channel = 0, d = ptr, n = c->length/sizeof(int32_t); n > 0; d++, n--) {
-                int64_t t;
+                sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF);
+                *((uint8_t*) data) = (uint8_t) st_13linear2alaw((int16_t) sum >> 3);
 
 
-                t = (int64_t)(*d);
-                t = (t * linear[channel]) / 0x10000;
-                t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
-                *d = (int32_t) t;
+                data = (uint8_t*) data + 1;
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
             }
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
             }
+
             break;
         }
 
             break;
         }
 
-        case PA_SAMPLE_S32RE: {
-            int32_t *d;
-            size_t n;
-            unsigned channel;
-            int32_t linear[PA_CHANNELS_MAX];
-
-            calc_linear_integer_volume(linear, volume);
+        case PA_SAMPLE_FLOAT32NE: {
+            unsigned channel = 0;
 
 
-            for (channel = 0, d = ptr, n = c->length/sizeof(int32_t); n > 0; d++, n--) {
-                int64_t t;
+            calc_linear_float_stream_volumes(streams, nstreams, volume, spec);
 
 
-                t = (int64_t)(PA_INT32_SWAP(*d));
-                t = (t * linear[channel]) / 0x10000;
-                t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
-                *d = PA_INT32_SWAP((int32_t) t);
+            while (data < end) {
+                float sum = 0;
+                unsigned i;
 
 
-                if (PA_UNLIKELY(++channel >= spec->channels))
-                    channel = 0;
-            }
+                for (i = 0; i < nstreams; i++) {
+                    pa_mix_info *m = streams + i;
+                    float v, cv = m->linear[channel].f;
 
 
-            break;
-        }
+                    if (PA_UNLIKELY(cv <= 0))
+                        continue;
 
 
-        case PA_SAMPLE_U8: {
-            uint8_t *d;
-            size_t n;
-            unsigned channel;
-            int32_t linear[PA_CHANNELS_MAX];
+                    v = *((float*) m->ptr);
+                    v *= cv;
+                    sum += v;
 
 
-            calc_linear_integer_volume(linear, volume);
+                    m->ptr = (uint8_t*) m->ptr + sizeof(float);
+                }
 
 
-            for (channel = 0, d = ptr, n = c->length; n > 0; d++, n--) {
-                int32_t t;
+                *((float*) data) = sum;
 
 
-                t = (int32_t) *d - 0x80;
-                t = (t * linear[channel]) / 0x10000;
-                t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F);
-                *d = (uint8_t) (t + 0x80);
+                data = (uint8_t*) data + sizeof(float);
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
             }
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
             }
+
             break;
         }
 
             break;
         }
 
-        case PA_SAMPLE_ULAW: {
-            uint8_t *d;
-            size_t n;
-            unsigned channel;
-            int32_t linear[PA_CHANNELS_MAX];
+        case PA_SAMPLE_FLOAT32RE: {
+            unsigned channel = 0;
 
 
-            calc_linear_integer_volume(linear, volume);
+            calc_linear_float_stream_volumes(streams, nstreams, volume, spec);
 
 
-            for (channel = 0, d = ptr, n = c->length; n > 0; d++, n--) {
-                int32_t t;
+            while (data < end) {
+                float sum = 0;
+                unsigned i;
 
 
-                t = (int32_t) st_ulaw2linear16(*d);
-                t = (t * linear[channel]) / 0x10000;
-                t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
-                *d = (uint8_t) st_14linear2ulaw(t >> 2);
+                for (i = 0; i < nstreams; i++) {
+                    pa_mix_info *m = streams + i;
+                    float v, cv = m->linear[channel].f;
 
 
-                if (PA_UNLIKELY(++channel >= spec->channels))
-                    channel = 0;
-            }
-            break;
-        }
+                    if (PA_UNLIKELY(cv <= 0))
+                        continue;
 
 
-        case PA_SAMPLE_ALAW: {
-            uint8_t *d;
-            size_t n;
-            unsigned channel;
-            int32_t linear[PA_CHANNELS_MAX];
+                    v = PA_FLOAT32_SWAP(*(float*) m->ptr);
+                    v *= cv;
+                    sum += v;
 
 
-            calc_linear_integer_volume(linear, volume);
+                    m->ptr = (uint8_t*) m->ptr + sizeof(float);
+                }
 
 
-            for (channel = 0, d = ptr, n = c->length; n > 0; d++, n--) {
-                int32_t t;
+                *((float*) data) = PA_FLOAT32_SWAP(sum);
 
 
-                t = (int32_t) st_alaw2linear16(*d);
-                t = (t * linear[channel]) / 0x10000;
-                t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
-                *d = (uint8_t) st_13linear2alaw(t >> 3);
+                data = (uint8_t*) data + sizeof(float);
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
             }
 
                 if (PA_UNLIKELY(++channel >= spec->channels))
                     channel = 0;
             }
+
             break;
         }
 
             break;
         }
 
-        case PA_SAMPLE_FLOAT32NE: {
-            float *d;
-            int skip;
-            unsigned n;
-            unsigned channel;
+        default:
+            pa_log_error("Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format));
+            pa_assert_not_reached();
+    }
 
 
-            d = ptr;
-            skip = spec->channels * sizeof(float);
-            n = c->length/sizeof(float)/spec->channels;
+    for (k = 0; k < nstreams; k++)
+        pa_memblock_release(streams[k].chunk.memblock);
 
 
-            for (channel = 0; channel < spec->channels; channel ++) {
-                float v, *t;
+    return length;
+}
 
 
-                if (PA_UNLIKELY(volume->values[channel] == PA_VOLUME_NORM))
-                    continue;
+typedef union {
+  float f;
+  uint32_t i;
+} volume_val;
+
+typedef void (*pa_calc_volume_func_t) (void *volumes, const pa_cvolume *volume);
+
+static const pa_calc_volume_func_t calc_volume_table[] = {
+  [PA_SAMPLE_U8]        = (pa_calc_volume_func_t) calc_linear_integer_volume,
+  [PA_SAMPLE_ALAW]      = (pa_calc_volume_func_t) calc_linear_integer_volume,
+  [PA_SAMPLE_ULAW]      = (pa_calc_volume_func_t) calc_linear_integer_volume,
+  [PA_SAMPLE_S16LE]     = (pa_calc_volume_func_t) calc_linear_integer_volume,
+  [PA_SAMPLE_S16BE]     = (pa_calc_volume_func_t) calc_linear_integer_volume,
+  [PA_SAMPLE_FLOAT32LE] = (pa_calc_volume_func_t) calc_linear_float_volume,
+  [PA_SAMPLE_FLOAT32BE] = (pa_calc_volume_func_t) calc_linear_float_volume,
+  [PA_SAMPLE_S32LE]     = (pa_calc_volume_func_t) calc_linear_integer_volume,
+  [PA_SAMPLE_S32BE]     = (pa_calc_volume_func_t) calc_linear_integer_volume,
+  [PA_SAMPLE_S24LE]     = (pa_calc_volume_func_t) calc_linear_integer_volume,
+  [PA_SAMPLE_S24BE]     = (pa_calc_volume_func_t) calc_linear_integer_volume,
+  [PA_SAMPLE_S24_32LE]  = (pa_calc_volume_func_t) calc_linear_integer_volume,
+  [PA_SAMPLE_S24_32BE]  = (pa_calc_volume_func_t) calc_linear_integer_volume
+};
 
 
-                v = (float) pa_sw_volume_to_linear(volume->values[channel]);
-                t = d + channel;
-                oil_scalarmult_f32(t, skip, t, skip, &v, n);
-            }
-            break;
-        }
+void pa_volume_memchunk(
+        pa_memchunk*c,
+        const pa_sample_spec *spec,
+        const pa_cvolume *volume) {
 
 
-        case PA_SAMPLE_FLOAT32RE: {
-            uint32_t *d;
-            size_t n;
-            unsigned channel;
-            float linear[PA_CHANNELS_MAX];
+    void *ptr;
+    volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING];
+    pa_do_volume_func_t do_volume;
 
 
-            calc_linear_float_volume(linear, volume);
+    pa_assert(c);
+    pa_assert(spec);
+    pa_assert(c->length % pa_frame_size(spec) == 0);
+    pa_assert(volume);
 
 
-            for (channel = 0, d = ptr, n = c->length/sizeof(float); n > 0; d++, n--) {
-                float t;
-                uint32_t z;
+    if (pa_memblock_is_silence(c->memblock))
+        return;
 
 
-                z = PA_UINT32_SWAP(*d);
-                t = *(float*) &z;
-                t *= linear[channel];
-                z = *(uint32_t*) &t;
-                *d = PA_UINT32_SWAP(z);
+    if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
+        return;
 
 
-                if (PA_UNLIKELY(++channel >= spec->channels))
-                    channel = 0;
-            }
+    if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
+        pa_silence_memchunk(c, spec);
+        return;
+    }
 
 
-            break;
-        }
+    if (spec->format < 0 || spec->format > PA_SAMPLE_MAX) {
+      pa_log_warn(" Unable to change volume of format %s.", pa_sample_format_to_string(spec->format));
+      return;
+    }
 
 
+    do_volume = pa_get_volume_func(spec->format);
+    pa_assert(do_volume);
 
 
-        default:
-            pa_log_warn(" Unable to change volume of format %s.", pa_sample_format_to_string(spec->format));
-            /* If we cannot change the volume, we just don't do it */
-    }
+    calc_volume_table[spec->format] ((void *)linear, volume);
+
+    ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index;
+
+    do_volume (ptr, (void *)linear, spec->channels, c->length);
 
     pa_memblock_release(c->memblock);
 }
 
     pa_memblock_release(c->memblock);
 }
@@ -846,7 +774,7 @@ size_t pa_frame_align(size_t l, const pa_sample_spec *ss) {
     return (l/fs) * fs;
 }
 
     return (l/fs) * fs;
 }
 
-int pa_frame_aligned(size_t l, const pa_sample_spec *ss) {
+pa_bool_t pa_frame_aligned(size_t l, const pa_sample_spec *ss) {
     size_t fs;
 
     pa_assert(ss);
     size_t fs;
 
     pa_assert(ss);
@@ -877,7 +805,7 @@ void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, u
         d = (uint8_t*) dst + c * ss;
 
         for (j = 0; j < n; j ++) {
         d = (uint8_t*) dst + c * ss;
 
         for (j = 0; j < n; j ++) {
-            oil_memcpy(d, s, ss);
+            memcpy(d, s, (int) ss);
             s = (uint8_t*) s + ss;
             d = (uint8_t*) d + fs;
         }
             s = (uint8_t*) s + ss;
             d = (uint8_t*) d + fs;
         }
@@ -905,7 +833,7 @@ void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss,
         d = dst[c];
 
         for (j = 0; j < n; j ++) {
         d = dst[c];
 
         for (j = 0; j < n; j ++) {
-            oil_memcpy(d, s, ss);
+            memcpy(d, s, (int) ss);
             s = (uint8_t*) s + fs;
             d = (uint8_t*) d + ss;
         }
             s = (uint8_t*) s + fs;
             d = (uint8_t*) d + ss;
         }
@@ -966,12 +894,20 @@ pa_memchunk* pa_silence_memchunk_get(pa_silence_cache *cache, pa_mempool *pool,
             case PA_SAMPLE_S16BE:
             case PA_SAMPLE_S32LE:
             case PA_SAMPLE_S32BE:
             case PA_SAMPLE_S16BE:
             case PA_SAMPLE_S32LE:
             case PA_SAMPLE_S32BE:
+            case PA_SAMPLE_S24LE:
+            case PA_SAMPLE_S24BE:
+            case PA_SAMPLE_S24_32LE:
+            case PA_SAMPLE_S24_32BE:
             case PA_SAMPLE_FLOAT32LE:
             case PA_SAMPLE_FLOAT32BE:
                 cache->blocks[PA_SAMPLE_S16LE] = b = silence_memblock_new(pool, 0);
                 cache->blocks[PA_SAMPLE_S16BE] = pa_memblock_ref(b);
                 cache->blocks[PA_SAMPLE_S32LE] = pa_memblock_ref(b);
                 cache->blocks[PA_SAMPLE_S32BE] = pa_memblock_ref(b);
             case PA_SAMPLE_FLOAT32LE:
             case PA_SAMPLE_FLOAT32BE:
                 cache->blocks[PA_SAMPLE_S16LE] = b = silence_memblock_new(pool, 0);
                 cache->blocks[PA_SAMPLE_S16BE] = pa_memblock_ref(b);
                 cache->blocks[PA_SAMPLE_S32LE] = pa_memblock_ref(b);
                 cache->blocks[PA_SAMPLE_S32BE] = pa_memblock_ref(b);
+                cache->blocks[PA_SAMPLE_S24LE] = pa_memblock_ref(b);
+                cache->blocks[PA_SAMPLE_S24BE] = pa_memblock_ref(b);
+                cache->blocks[PA_SAMPLE_S24_32LE] = pa_memblock_ref(b);
+                cache->blocks[PA_SAMPLE_S24_32BE] = pa_memblock_ref(b);
                 cache->blocks[PA_SAMPLE_FLOAT32LE] = pa_memblock_ref(b);
                 cache->blocks[PA_SAMPLE_FLOAT32BE] = pa_memblock_ref(b);
                 break;
                 cache->blocks[PA_SAMPLE_FLOAT32LE] = pa_memblock_ref(b);
                 cache->blocks[PA_SAMPLE_FLOAT32BE] = pa_memblock_ref(b);
                 break;
@@ -1006,10 +942,15 @@ void pa_sample_clamp(pa_sample_format_t format, void *dst, size_t dstr, const vo
     s = src; d = dst;
 
     if (format == PA_SAMPLE_FLOAT32NE) {
     s = src; d = dst;
 
     if (format == PA_SAMPLE_FLOAT32NE) {
+        for (; n > 0; n--) {
+            float f;
 
 
-        float minus_one = -1.0, plus_one = 1.0;
-        oil_clip_f32(d, dstr, s, sstr, n, &minus_one, &plus_one);
+            f = *s;
+            *d = PA_CLAMP_UNLIKELY(f, -1.0f, 1.0f);
 
 
+            s = (const float*) ((const uint8_t*) s + sstr);
+            d = (float*) ((uint8_t*) d + dstr);
+        }
     } else {
         pa_assert(format == PA_SAMPLE_FLOAT32RE);
 
     } else {
         pa_assert(format == PA_SAMPLE_FLOAT32RE);
 
@@ -1017,7 +958,7 @@ void pa_sample_clamp(pa_sample_format_t format, void *dst, size_t dstr, const vo
             float f;
 
             f = PA_FLOAT32_SWAP(*s);
             float f;
 
             f = PA_FLOAT32_SWAP(*s);
-            f = PA_CLAMP_UNLIKELY(f, -1.0, 1.0);
+            f = PA_CLAMP_UNLIKELY(f, -1.0f, 1.0f);
             *d = PA_FLOAT32_SWAP(f);
 
             s = (const float*) ((const uint8_t*) s + sstr);
             *d = PA_FLOAT32_SWAP(f);
 
             s = (const float*) ((const uint8_t*) s + sstr);
@@ -1025,3 +966,103 @@ void pa_sample_clamp(pa_sample_format_t format, void *dst, size_t dstr, const vo
         }
     }
 }
         }
     }
 }
+
+/* Similar to pa_bytes_to_usec() but rounds up, not down */
+
+pa_usec_t pa_bytes_to_usec_round_up(uint64_t length, const pa_sample_spec *spec) {
+    size_t fs;
+    pa_usec_t usec;
+
+    pa_assert(spec);
+
+    fs = pa_frame_size(spec);
+    length = (length + fs - 1) / fs;
+
+    usec = (pa_usec_t) length * PA_USEC_PER_SEC;
+
+    return (usec + spec->rate - 1) / spec->rate;
+}
+
+/* Similar to pa_usec_to_bytes() but rounds up, not down */
+
+size_t pa_usec_to_bytes_round_up(pa_usec_t t, const pa_sample_spec *spec) {
+    uint64_t u;
+    pa_assert(spec);
+
+    u = (uint64_t) t * (uint64_t) spec->rate;
+
+    u = (u + PA_USEC_PER_SEC - 1) / PA_USEC_PER_SEC;
+
+    u *= pa_frame_size(spec);
+
+    return (size_t) u;
+}
+
+void pa_memchunk_dump_to_file(pa_memchunk *c, const char *fn) {
+    FILE *f;
+    void *p;
+
+    pa_assert(c);
+    pa_assert(fn);
+
+    /* Only for debugging purposes */
+
+    f = pa_fopen_cloexec(fn, "a");
+
+    if (!f) {
+        pa_log_warn("Failed to open '%s': %s", fn, pa_cstrerror(errno));
+        return;
+    }
+
+    p = pa_memblock_acquire(c->memblock);
+
+    if (fwrite((uint8_t*) p + c->index, 1, c->length, f) != c->length)
+        pa_log_warn("Failed to write to '%s': %s", fn, pa_cstrerror(errno));
+
+    pa_memblock_release(c->memblock);
+
+    fclose(f);
+}
+
+static void calc_sine(float *f, size_t l, double freq) {
+    size_t i;
+
+    l /= sizeof(float);
+
+    for (i = 0; i < l; i++)
+        *(f++) = (float) 0.5f * sin((double) i*M_PI*2*freq / (double) l);
+}
+
+void pa_memchunk_sine(pa_memchunk *c, pa_mempool *pool, unsigned rate, unsigned freq) {
+    size_t l;
+    unsigned gcd, n;
+    void *p;
+
+    pa_memchunk_reset(c);
+
+    gcd = pa_gcd(rate, freq);
+    n = rate / gcd;
+
+    l = pa_mempool_block_size_max(pool) / sizeof(float);
+
+    l /= n;
+    if (l <= 0) l = 1;
+    l *= n;
+
+    c->length = l * sizeof(float);
+    c->memblock = pa_memblock_new(pool, c->length);
+
+    p = pa_memblock_acquire(c->memblock);
+    calc_sine(p, c->length, freq * l / rate);
+    pa_memblock_release(c->memblock);
+}
+
+size_t pa_convert_size(size_t size, const pa_sample_spec *from, const pa_sample_spec *to) {
+    pa_usec_t usec;
+
+    pa_assert(from);
+    pa_assert(to);
+
+    usec = pa_bytes_to_usec_round_up(size, from);
+    return pa_usec_to_bytes_round_up(usec, to);
+}