]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/resampler.c
resamplers: Use fastpath assert in trivial resampler
[pulseaudio] / src / pulsecore / resampler.c
index f0515ebe8e9fbb06938bcc5a88fde77126e194c5..c3b6df11f5cdbde6fc8c602a4af4059591dff5d2 100644 (file)
@@ -5,7 +5,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 <string.h>
 
 
 #include <string.h>
 
-#if HAVE_LIBSAMPLERATE
+#ifdef HAVE_LIBSAMPLERATE
 #include <samplerate.h>
 #endif
 
 #include <speex/speex_resampler.h>
 
 #include <samplerate.h>
 #endif
 
 #include <speex/speex_resampler.h>
 
-#include <liboil/liboilfuncs.h>
-#include <liboil/liboil.h>
-
 #include <pulse/xmalloc.h>
 #include <pulsecore/sconv.h>
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/strbuf.h>
 #include <pulse/xmalloc.h>
 #include <pulsecore/sconv.h>
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/strbuf.h>
+#include <pulsecore/remap.h>
 
 #include "ffmpeg/avcodec.h"
 
 
 #include "ffmpeg/avcodec.h"
 
@@ -64,7 +62,7 @@ struct pa_resampler {
     pa_convert_func_t to_work_format_func;
     pa_convert_func_t from_work_format_func;
 
     pa_convert_func_t to_work_format_func;
     pa_convert_func_t from_work_format_func;
 
-    float map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX];
+    pa_remap_t remap;
     pa_bool_t map_required;
 
     void (*impl_free)(pa_resampler *r);
     pa_bool_t map_required;
 
     void (*impl_free)(pa_resampler *r);
@@ -156,16 +154,6 @@ static int (* const init_table[])(pa_resampler*r) = {
     [PA_RESAMPLER_PEAKS]                   = peaks_init,
 };
 
     [PA_RESAMPLER_PEAKS]                   = peaks_init,
 };
 
-static inline size_t sample_size(pa_sample_format_t f) {
-    pa_sample_spec ss = {
-        .format = f,
-        .rate = 0,
-        .channels = 1
-    };
-
-    return pa_sample_size(&ss);
-}
-
 pa_resampler* pa_resampler_new(
         pa_mempool *pool,
         const pa_sample_spec *a,
 pa_resampler* pa_resampler_new(
         pa_mempool *pool,
         const pa_sample_spec *a,
@@ -224,6 +212,11 @@ pa_resampler* pa_resampler_new(
     r->i_ss = *a;
     r->o_ss = *b;
 
     r->i_ss = *a;
     r->o_ss = *b;
 
+    /* set up the remap structure */
+    r->remap.i_ss = &r->i_ss;
+    r->remap.o_ss = &r->o_ss;
+    r->remap.format = &r->work_format;
+
     if (am)
         r->i_cm = *am;
     else if (!pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels, PA_CHANNEL_MAP_DEFAULT))
     if (am)
         r->i_cm = *am;
     else if (!pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels, PA_CHANNEL_MAP_DEFAULT))
@@ -257,8 +250,12 @@ pa_resampler* pa_resampler_new(
 
             if (a->format == PA_SAMPLE_S32NE || a->format == PA_SAMPLE_S32RE ||
                 a->format == PA_SAMPLE_FLOAT32NE || a->format == PA_SAMPLE_FLOAT32RE ||
 
             if (a->format == PA_SAMPLE_S32NE || a->format == PA_SAMPLE_S32RE ||
                 a->format == PA_SAMPLE_FLOAT32NE || a->format == PA_SAMPLE_FLOAT32RE ||
+                a->format == PA_SAMPLE_S24NE || a->format == PA_SAMPLE_S24RE ||
+                a->format == PA_SAMPLE_S24_32NE || a->format == PA_SAMPLE_S24_32RE ||
                 b->format == PA_SAMPLE_S32NE || b->format == PA_SAMPLE_S32RE ||
                 b->format == PA_SAMPLE_S32NE || b->format == PA_SAMPLE_S32RE ||
-                b->format == PA_SAMPLE_FLOAT32NE || b->format == PA_SAMPLE_FLOAT32RE)
+                b->format == PA_SAMPLE_FLOAT32NE || b->format == PA_SAMPLE_FLOAT32RE ||
+                b->format == PA_SAMPLE_S24NE || b->format == PA_SAMPLE_S24RE ||
+                b->format == PA_SAMPLE_S24_32NE || b->format == PA_SAMPLE_S24_32RE)
                 r->work_format = PA_SAMPLE_FLOAT32NE;
             else
                 r->work_format = PA_SAMPLE_S16NE;
                 r->work_format = PA_SAMPLE_FLOAT32NE;
             else
                 r->work_format = PA_SAMPLE_S16NE;
@@ -271,7 +268,7 @@ pa_resampler* pa_resampler_new(
 
     pa_log_info("Using %s as working format.", pa_sample_format_to_string(r->work_format));
 
 
     pa_log_info("Using %s as working format.", pa_sample_format_to_string(r->work_format));
 
-    r->w_sz = sample_size(r->work_format);
+    r->w_sz = pa_sample_size_of_format(r->work_format);
 
     if (r->i_ss.format == r->work_format)
         r->to_work_format_func = NULL;
 
     if (r->i_ss.format == r->work_format)
         r->to_work_format_func = NULL;
@@ -302,8 +299,7 @@ pa_resampler* pa_resampler_new(
     return r;
 
 fail:
     return r;
 
 fail:
-    if (r)
-        pa_xfree(r);
+    pa_xfree(r);
 
     return NULL;
 }
 
     return NULL;
 }
@@ -353,13 +349,17 @@ void pa_resampler_set_output_rate(pa_resampler *r, uint32_t rate) {
 size_t pa_resampler_request(pa_resampler *r, size_t out_length) {
     pa_assert(r);
 
 size_t pa_resampler_request(pa_resampler *r, size_t out_length) {
     pa_assert(r);
 
-    return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz;
+    /* Let's round up here */
+
+    return (((((out_length + r->o_fz-1) / r->o_fz) * r->i_ss.rate) + r->o_ss.rate-1) / r->o_ss.rate) * r->i_fz;
 }
 
 size_t pa_resampler_result(pa_resampler *r, size_t in_length) {
     pa_assert(r);
 
 }
 
 size_t pa_resampler_result(pa_resampler *r, size_t in_length) {
     pa_assert(r);
 
-    return (((in_length / r->i_fz)*r->o_ss.rate)/r->i_ss.rate) * r->o_fz;
+    /* Let's round up here */
+
+    return (((((in_length + r->i_fz-1) / r->i_fz) * r->o_ss.rate) + r->i_ss.rate-1) / r->i_ss.rate) * r->o_fz;
 }
 
 size_t pa_resampler_max_block_size(pa_resampler *r) {
 }
 
 size_t pa_resampler_max_block_size(pa_resampler *r) {
@@ -399,6 +399,30 @@ pa_resample_method_t pa_resampler_get_method(pa_resampler *r) {
     return r->method;
 }
 
     return r->method;
 }
 
+const pa_channel_map* pa_resampler_input_channel_map(pa_resampler *r) {
+    pa_assert(r);
+
+    return &r->i_cm;
+}
+
+const pa_sample_spec* pa_resampler_input_sample_spec(pa_resampler *r) {
+    pa_assert(r);
+
+    return &r->i_ss;
+}
+
+const pa_channel_map* pa_resampler_output_channel_map(pa_resampler *r) {
+    pa_assert(r);
+
+    return &r->o_cm;
+}
+
+const pa_sample_spec* pa_resampler_output_sample_spec(pa_resampler *r) {
+    pa_assert(r);
+
+    return &r->o_ss;
+}
+
 static const char * const resample_methods[] = {
     "src-sinc-best-quality",
     "src-sinc-medium-quality",
 static const char * const resample_methods[] = {
     "src-sinc-best-quality",
     "src-sinc-medium-quality",
@@ -558,32 +582,41 @@ static int front_rear_side(pa_channel_position_t p) {
 
 static void calc_map_table(pa_resampler *r) {
     unsigned oc, ic;
 
 static void calc_map_table(pa_resampler *r) {
     unsigned oc, ic;
+    unsigned n_oc, n_ic;
     pa_bool_t ic_connected[PA_CHANNELS_MAX];
     pa_bool_t remix;
     pa_strbuf *s;
     char *t;
     pa_bool_t ic_connected[PA_CHANNELS_MAX];
     pa_bool_t remix;
     pa_strbuf *s;
     char *t;
+    pa_remap_t *m;
 
     pa_assert(r);
 
     if (!(r->map_required = (r->i_ss.channels != r->o_ss.channels || (!(r->flags & PA_RESAMPLER_NO_REMAP) && !pa_channel_map_equal(&r->i_cm, &r->o_cm)))))
         return;
 
 
     pa_assert(r);
 
     if (!(r->map_required = (r->i_ss.channels != r->o_ss.channels || (!(r->flags & PA_RESAMPLER_NO_REMAP) && !pa_channel_map_equal(&r->i_cm, &r->o_cm)))))
         return;
 
-    memset(r->map_table, 0, sizeof(r->map_table));
+    m = &r->remap;
+
+    n_oc = r->o_ss.channels;
+    n_ic = r->i_ss.channels;
+
+    memset(m->map_table_f, 0, sizeof(m->map_table_f));
+    memset(m->map_table_i, 0, sizeof(m->map_table_i));
+
     memset(ic_connected, 0, sizeof(ic_connected));
     remix = (r->flags & (PA_RESAMPLER_NO_REMAP|PA_RESAMPLER_NO_REMIX)) == 0;
 
     memset(ic_connected, 0, sizeof(ic_connected));
     remix = (r->flags & (PA_RESAMPLER_NO_REMAP|PA_RESAMPLER_NO_REMIX)) == 0;
 
-    for (oc = 0; oc < r->o_ss.channels; oc++) {
+    for (oc = 0; oc < n_oc; oc++) {
         pa_bool_t oc_connected = FALSE;
         pa_channel_position_t b = r->o_cm.map[oc];
 
         pa_bool_t oc_connected = FALSE;
         pa_channel_position_t b = r->o_cm.map[oc];
 
-        for (ic = 0; ic < r->i_ss.channels; ic++) {
+        for (ic = 0; ic < n_ic; ic++) {
             pa_channel_position_t a = r->i_cm.map[ic];
 
             if (r->flags & PA_RESAMPLER_NO_REMAP) {
                 /* We shall not do any remapping. Hence, just check by index */
 
                 if (ic == oc)
             pa_channel_position_t a = r->i_cm.map[ic];
 
             if (r->flags & PA_RESAMPLER_NO_REMAP) {
                 /* We shall not do any remapping. Hence, just check by index */
 
                 if (ic == oc)
-                    r->map_table[oc][ic] = 1.0;
+                    m->map_table_f[oc][ic] = 1.0;
 
                 continue;
             }
 
                 continue;
             }
@@ -592,7 +625,7 @@ static void calc_map_table(pa_resampler *r) {
                 /* We shall not do any remixing. Hence, just check by name */
 
                 if (a == b)
                 /* We shall not do any remixing. Hence, just check by name */
 
                 if (a == b)
-                    r->map_table[oc][ic] = 1.0;
+                    m->map_table_f[oc][ic] = 1.0;
 
                 continue;
             }
 
                 continue;
             }
@@ -612,7 +645,7 @@ static void calc_map_table(pa_resampler *r) {
              * volume will not match, and the two channels will be a
              * linear combination of both.
              *
              * volume will not match, and the two channels will be a
              * linear combination of both.
              *
-             * This is losely based on random suggestions found on the
+             * This is loosely based on random suggestions found on the
              * Internet, such as this:
              * http://www.halfgaar.net/surround-sound-in-linux and the
              * alsa upmix plugin.
              * Internet, such as this:
              * http://www.halfgaar.net/surround-sound-in-linux and the
              * alsa upmix plugin.
@@ -667,7 +700,7 @@ static void calc_map_table(pa_resampler *r) {
              */
 
             if (a == b || a == PA_CHANNEL_POSITION_MONO || b == PA_CHANNEL_POSITION_MONO) {
              */
 
             if (a == b || a == PA_CHANNEL_POSITION_MONO || b == PA_CHANNEL_POSITION_MONO) {
-                r->map_table[oc][ic] = 1.0;
+                m->map_table_f[oc][ic] = 1.0;
 
                 oc_connected = TRUE;
                 ic_connected[ic] = TRUE;
 
                 oc_connected = TRUE;
                 ic_connected[ic] = TRUE;
@@ -685,14 +718,14 @@ static void calc_map_table(pa_resampler *r) {
                 /* We are not connected and on the left side, let's
                  * average all left side input channels. */
 
                 /* We are not connected and on the left side, let's
                  * average all left side input channels. */
 
-                for (ic = 0; ic < r->i_ss.channels; ic++)
+                for (ic = 0; ic < n_ic; ic++)
                     if (on_left(r->i_cm.map[ic]))
                         n++;
 
                 if (n > 0)
                     if (on_left(r->i_cm.map[ic]))
                         n++;
 
                 if (n > 0)
-                    for (ic = 0; ic < r->i_ss.channels; ic++)
+                    for (ic = 0; ic < n_ic; ic++)
                         if (on_left(r->i_cm.map[ic])) {
                         if (on_left(r->i_cm.map[ic])) {
-                            r->map_table[oc][ic] = 1.0f / (float) n;
+                            m->map_table_f[oc][ic] = 1.0f / (float) n;
                             ic_connected[ic] = TRUE;
                         }
 
                             ic_connected[ic] = TRUE;
                         }
 
@@ -706,14 +739,14 @@ static void calc_map_table(pa_resampler *r) {
                 /* We are not connected and on the right side, let's
                  * average all right side input channels. */
 
                 /* We are not connected and on the right side, let's
                  * average all right side input channels. */
 
-                for (ic = 0; ic < r->i_ss.channels; ic++)
+                for (ic = 0; ic < n_ic; ic++)
                     if (on_right(r->i_cm.map[ic]))
                         n++;
 
                 if (n > 0)
                     if (on_right(r->i_cm.map[ic]))
                         n++;
 
                 if (n > 0)
-                    for (ic = 0; ic < r->i_ss.channels; ic++)
+                    for (ic = 0; ic < n_ic; ic++)
                         if (on_right(r->i_cm.map[ic])) {
                         if (on_right(r->i_cm.map[ic])) {
-                            r->map_table[oc][ic] = 1.0f / (float) n;
+                            m->map_table_f[oc][ic] = 1.0f / (float) n;
                             ic_connected[ic] = TRUE;
                         }
 
                             ic_connected[ic] = TRUE;
                         }
 
@@ -727,14 +760,14 @@ static void calc_map_table(pa_resampler *r) {
                 /* We are not connected and at the center. Let's
                  * average all center input channels. */
 
                 /* We are not connected and at the center. Let's
                  * average all center input channels. */
 
-                for (ic = 0; ic < r->i_ss.channels; ic++)
+                for (ic = 0; ic < n_ic; ic++)
                     if (on_center(r->i_cm.map[ic]))
                         n++;
 
                 if (n > 0) {
                     if (on_center(r->i_cm.map[ic]))
                         n++;
 
                 if (n > 0) {
-                    for (ic = 0; ic < r->i_ss.channels; ic++)
+                    for (ic = 0; ic < n_ic; ic++)
                         if (on_center(r->i_cm.map[ic])) {
                         if (on_center(r->i_cm.map[ic])) {
-                            r->map_table[oc][ic] = 1.0f / (float) n;
+                            m->map_table_f[oc][ic] = 1.0f / (float) n;
                             ic_connected[ic] = TRUE;
                         }
                 } else {
                             ic_connected[ic] = TRUE;
                         }
                 } else {
@@ -744,14 +777,14 @@ static void calc_map_table(pa_resampler *r) {
 
                     n = 0;
 
 
                     n = 0;
 
-                    for (ic = 0; ic < r->i_ss.channels; ic++)
+                    for (ic = 0; ic < n_ic; ic++)
                         if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic]))
                             n++;
 
                     if (n > 0)
                         if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic]))
                             n++;
 
                     if (n > 0)
-                        for (ic = 0; ic < r->i_ss.channels; ic++)
+                        for (ic = 0; ic < n_ic; ic++)
                             if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic])) {
                             if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic])) {
-                                r->map_table[oc][ic] = 1.0f / (float) n;
+                                m->map_table_f[oc][ic] = 1.0f / (float) n;
                                 ic_connected[ic] = TRUE;
                             }
 
                                 ic_connected[ic] = TRUE;
                             }
 
@@ -765,12 +798,12 @@ static void calc_map_table(pa_resampler *r) {
                 /* We are not connected and an LFE. Let's average all
                  * channels for LFE. */
 
                 /* We are not connected and an LFE. Let's average all
                  * channels for LFE. */
 
-                for (ic = 0; ic < r->i_ss.channels; ic++) {
+                for (ic = 0; ic < n_ic; ic++) {
 
                     if (!(r->flags & PA_RESAMPLER_NO_LFE))
 
                     if (!(r->flags & PA_RESAMPLER_NO_LFE))
-                        r->map_table[oc][ic] = 1.0f / (float) r->i_ss.channels;
+                        m->map_table_f[oc][ic] = 1.0f / (float) n_ic;
                     else
                     else
-                        r->map_table[oc][ic] = 0;
+                        m->map_table_f[oc][ic] = 0;
 
                     /* Please note that a channel connected to LFE
                      * doesn't really count as connected. */
 
                     /* Please note that a channel connected to LFE
                      * doesn't really count as connected. */
@@ -786,7 +819,7 @@ static void calc_map_table(pa_resampler *r) {
             ic_unconnected_center = 0,
             ic_unconnected_lfe = 0;
 
             ic_unconnected_center = 0,
             ic_unconnected_lfe = 0;
 
-        for (ic = 0; ic < r->i_ss.channels; ic++) {
+        for (ic = 0; ic < n_ic; ic++) {
             pa_channel_position_t a = r->i_cm.map[ic];
 
             if (ic_connected[ic])
             pa_channel_position_t a = r->i_cm.map[ic];
 
             if (ic_connected[ic])
@@ -807,22 +840,22 @@ static void calc_map_table(pa_resampler *r) {
             /* OK, so there are unconnected input channels on the
              * left. Let's multiply all already connected channels on
              * the left side by .9 and add in our averaged unconnected
             /* OK, so there are unconnected input channels on the
              * left. Let's multiply all already connected channels on
              * the left side by .9 and add in our averaged unconnected
-             * channels multplied by .1 */
+             * channels multiplied by .1 */
 
 
-            for (oc = 0; oc < r->o_ss.channels; oc++) {
+            for (oc = 0; oc < n_oc; oc++) {
 
                 if (!on_left(r->o_cm.map[oc]))
                     continue;
 
 
                 if (!on_left(r->o_cm.map[oc]))
                     continue;
 
-                for (ic = 0; ic < r->i_ss.channels; ic++) {
+                for (ic = 0; ic < n_ic; ic++) {
 
                     if (ic_connected[ic]) {
 
                     if (ic_connected[ic]) {
-                        r->map_table[oc][ic] *= .9f;
+                        m->map_table_f[oc][ic] *= .9f;
                         continue;
                     }
 
                     if (on_left(r->i_cm.map[ic]))
                         continue;
                     }
 
                     if (on_left(r->i_cm.map[ic]))
-                        r->map_table[oc][ic] = .1f / (float) ic_unconnected_left;
+                        m->map_table_f[oc][ic] = .1f / (float) ic_unconnected_left;
                 }
             }
         }
                 }
             }
         }
@@ -832,22 +865,22 @@ static void calc_map_table(pa_resampler *r) {
             /* OK, so there are unconnected input channels on the
              * right. Let's multiply all already connected channels on
              * the right side by .9 and add in our averaged unconnected
             /* OK, so there are unconnected input channels on the
              * right. Let's multiply all already connected channels on
              * the right side by .9 and add in our averaged unconnected
-             * channels multplied by .1 */
+             * channels multiplied by .1 */
 
 
-            for (oc = 0; oc < r->o_ss.channels; oc++) {
+            for (oc = 0; oc < n_oc; oc++) {
 
                 if (!on_right(r->o_cm.map[oc]))
                     continue;
 
 
                 if (!on_right(r->o_cm.map[oc]))
                     continue;
 
-                for (ic = 0; ic < r->i_ss.channels; ic++) {
+                for (ic = 0; ic < n_ic; ic++) {
 
                     if (ic_connected[ic]) {
 
                     if (ic_connected[ic]) {
-                        r->map_table[oc][ic] *= .9f;
+                        m->map_table_f[oc][ic] *= .9f;
                         continue;
                     }
 
                     if (on_right(r->i_cm.map[ic]))
                         continue;
                     }
 
                     if (on_right(r->i_cm.map[ic]))
-                        r->map_table[oc][ic] = .1f / (float) ic_unconnected_right;
+                        m->map_table_f[oc][ic] = .1f / (float) ic_unconnected_right;
                 }
             }
         }
                 }
             }
         }
@@ -858,22 +891,22 @@ static void calc_map_table(pa_resampler *r) {
             /* OK, so there are unconnected input channels on the
              * center. Let's multiply all already connected channels on
              * the center side by .9 and add in our averaged unconnected
             /* OK, so there are unconnected input channels on the
              * center. Let's multiply all already connected channels on
              * the center side by .9 and add in our averaged unconnected
-             * channels multplied by .1 */
+             * channels multiplied by .1 */
 
 
-            for (oc = 0; oc < r->o_ss.channels; oc++) {
+            for (oc = 0; oc < n_oc; oc++) {
 
                 if (!on_center(r->o_cm.map[oc]))
                     continue;
 
 
                 if (!on_center(r->o_cm.map[oc]))
                     continue;
 
-                for (ic = 0; ic < r->i_ss.channels; ic++)  {
+                for (ic = 0; ic < n_ic; ic++) {
 
                     if (ic_connected[ic]) {
 
                     if (ic_connected[ic]) {
-                        r->map_table[oc][ic] *= .9f;
+                        m->map_table_f[oc][ic] *= .9f;
                         continue;
                     }
 
                     if (on_center(r->i_cm.map[ic])) {
                         continue;
                     }
 
                     if (on_center(r->i_cm.map[ic])) {
-                        r->map_table[oc][ic] = .1f / (float) ic_unconnected_center;
+                        m->map_table_f[oc][ic] = .1f / (float) ic_unconnected_center;
                         mixed_in = TRUE;
                     }
                 }
                         mixed_in = TRUE;
                     }
                 }
@@ -891,7 +924,7 @@ static void calc_map_table(pa_resampler *r) {
                    it into left and right. Using .375 and 0.75 as
                    factors. */
 
                    it into left and right. Using .375 and 0.75 as
                    factors. */
 
-                for (ic = 0; ic < r->i_ss.channels; ic++) {
+                for (ic = 0; ic < n_ic; ic++) {
 
                     if (ic_connected[ic])
                         continue;
 
                     if (ic_connected[ic])
                         continue;
@@ -899,7 +932,7 @@ static void calc_map_table(pa_resampler *r) {
                     if (!on_center(r->i_cm.map[ic]))
                         continue;
 
                     if (!on_center(r->i_cm.map[ic]))
                         continue;
 
-                    for (oc = 0; oc < r->o_ss.channels; oc++) {
+                    for (oc = 0; oc < n_oc; oc++) {
 
                         if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc]))
                             continue;
 
                         if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc]))
                             continue;
@@ -910,7 +943,7 @@ static void calc_map_table(pa_resampler *r) {
                         }
                     }
 
                         }
                     }
 
-                    for (oc = 0; oc < r->o_ss.channels; oc++) {
+                    for (oc = 0; oc < n_oc; oc++) {
 
                         if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc]))
                             continue;
 
                         if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc]))
                             continue;
@@ -920,7 +953,7 @@ static void calc_map_table(pa_resampler *r) {
                     }
                 }
 
                     }
                 }
 
-                for (oc = 0; oc < r->o_ss.channels; oc++) {
+                for (oc = 0; oc < n_oc; oc++) {
 
                     if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc]))
                         continue;
 
                     if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc]))
                         continue;
@@ -928,10 +961,10 @@ static void calc_map_table(pa_resampler *r) {
                     if (ncenter[oc] <= 0)
                         continue;
 
                     if (ncenter[oc] <= 0)
                         continue;
 
-                    for (ic = 0; ic < r->i_ss.channels; ic++)  {
+                    for (ic = 0; ic < n_ic; ic++) {
 
                         if (ic_connected[ic]) {
 
                         if (ic_connected[ic]) {
-                            r->map_table[oc][ic] *= .75f;
+                            m->map_table_f[oc][ic] *= .75f;
                             continue;
                         }
 
                             continue;
                         }
 
@@ -939,7 +972,7 @@ static void calc_map_table(pa_resampler *r) {
                             continue;
 
                         if (!found_frs[ic] || front_rear_side(r->i_cm.map[ic]) == front_rear_side(r->o_cm.map[oc]))
                             continue;
 
                         if (!found_frs[ic] || front_rear_side(r->i_cm.map[ic]) == front_rear_side(r->o_cm.map[oc]))
-                            r->map_table[oc][ic] = .375f / (float) ncenter[oc];
+                            m->map_table_f[oc][ic] = .375f / (float) ncenter[oc];
                     }
                 }
             }
                     }
                 }
             }
@@ -950,40 +983,46 @@ static void calc_map_table(pa_resampler *r) {
             /* OK, so there is an unconnected LFE channel. Let's mix
              * it into all channels, with factor 0.375 */
 
             /* OK, so there is an unconnected LFE channel. Let's mix
              * it into all channels, with factor 0.375 */
 
-            for (ic = 0; ic < r->i_ss.channels; ic++)  {
+            for (ic = 0; ic < n_ic; ic++) {
 
                 if (!on_lfe(r->i_cm.map[ic]))
                     continue;
 
 
                 if (!on_lfe(r->i_cm.map[ic]))
                     continue;
 
-                for (oc = 0; oc < r->o_ss.channels; oc++)
-                    r->map_table[oc][ic] = 0.375f / (float) ic_unconnected_lfe;
+                for (oc = 0; oc < n_oc; oc++)
+                    m->map_table_f[oc][ic] = 0.375f / (float) ic_unconnected_lfe;
             }
         }
     }
             }
         }
     }
-
+    /* make an 16:16 int version of the matrix */
+    for (oc = 0; oc < n_oc; oc++)
+        for (ic = 0; ic < n_ic; ic++)
+            m->map_table_i[oc][ic] = (int32_t) (m->map_table_f[oc][ic] * 0x10000);
 
     s = pa_strbuf_new();
 
     pa_strbuf_printf(s, "     ");
 
     s = pa_strbuf_new();
 
     pa_strbuf_printf(s, "     ");
-    for (ic = 0; ic < r->i_ss.channels; ic++)
+    for (ic = 0; ic < n_ic; ic++)
         pa_strbuf_printf(s, "  I%02u ", ic);
     pa_strbuf_puts(s, "\n    +");
 
         pa_strbuf_printf(s, "  I%02u ", ic);
     pa_strbuf_puts(s, "\n    +");
 
-    for (ic = 0; ic < r->i_ss.channels; ic++)
+    for (ic = 0; ic < n_ic; ic++)
         pa_strbuf_printf(s, "------");
     pa_strbuf_puts(s, "\n");
 
         pa_strbuf_printf(s, "------");
     pa_strbuf_puts(s, "\n");
 
-    for (oc = 0; oc < r->o_ss.channels; oc++) {
+    for (oc = 0; oc < n_oc; oc++) {
         pa_strbuf_printf(s, "O%02u |", oc);
 
         pa_strbuf_printf(s, "O%02u |", oc);
 
-        for (ic = 0; ic < r->i_ss.channels; ic++)
-            pa_strbuf_printf(s, " %1.3f", r->map_table[oc][ic]);
+        for (ic = 0; ic < n_ic; ic++)
+            pa_strbuf_printf(s, " %1.3f", m->map_table_f[oc][ic]);
 
         pa_strbuf_puts(s, "\n");
     }
 
     pa_log_debug("Channel matrix:\n%s", t = pa_strbuf_tostring_free(s));
     pa_xfree(t);
 
         pa_strbuf_puts(s, "\n");
     }
 
     pa_log_debug("Channel matrix:\n%s", t = pa_strbuf_tostring_free(s));
     pa_xfree(t);
+
+    /* initialize the remapping function */
+    pa_init_remap(m);
 }
 
 static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) {
 }
 
 static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) {
@@ -1023,41 +1062,10 @@ static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input)
     return &r->buf1;
 }
 
     return &r->buf1;
 }
 
-static void vectoradd_s16_with_fraction(
-        int16_t *d, int dstr,
-        const int16_t *s1, int sstr1,
-        const int16_t *s2, int sstr2,
-        int n,
-        float s3, float s4) {
-
-    int32_t i3, i4;
-
-    i3 = (int32_t) (s3 * 0x10000);
-    i4 = (int32_t) (s4 * 0x10000);
-
-    for (; n > 0; n--) {
-        int32_t a, b;
-
-        a = *s1;
-        b = *s2;
-
-        a = (a * i3) / 0x10000;
-        b = (b * i4) / 0x10000;
-
-        *d = (int16_t) (a + b);
-
-        s1 = (const int16_t*) ((const uint8_t*) s1 + sstr1);
-        s2 = (const int16_t*) ((const uint8_t*) s2 + sstr2);
-        d = (int16_t*) ((uint8_t*) d + dstr);
-
-    }
-}
-
 static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) {
     unsigned in_n_samples, out_n_samples, n_frames;
 static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) {
     unsigned in_n_samples, out_n_samples, n_frames;
-    int i_skip, o_skip;
-    unsigned oc;
     void *src, *dst;
     void *src, *dst;
+    pa_remap_t *remap;
 
     pa_assert(r);
     pa_assert(input);
 
     pa_assert(r);
     pa_assert(input);
@@ -1086,76 +1094,14 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) {
     src = ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
     dst = pa_memblock_acquire(r->buf2.memblock);
 
     src = ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
     dst = pa_memblock_acquire(r->buf2.memblock);
 
-    memset(dst, 0, r->buf2.length);
-
-    o_skip = (int) (r->w_sz * r->o_ss.channels);
-    i_skip = (int) (r->w_sz * r->i_ss.channels);
-
-    switch (r->work_format) {
-        case PA_SAMPLE_FLOAT32NE:
-
-            for (oc = 0; oc < r->o_ss.channels; oc++) {
-                unsigned ic;
-                static const float one = 1.0;
-
-                for (ic = 0; ic < r->i_ss.channels; ic++) {
-
-                    if (r->map_table[oc][ic] <= 0.0)
-                        continue;
-
-                    oil_vectoradd_f32(
-                            (float*) dst + oc, o_skip,
-                            (float*) dst + oc, o_skip,
-                            (float*) src + ic, i_skip,
-                            (int) n_frames,
-                            &one, &r->map_table[oc][ic]);
-                }
-            }
-
-            break;
-
-        case PA_SAMPLE_S16NE:
-
-            for (oc = 0; oc < r->o_ss.channels; oc++) {
-                unsigned ic;
+    remap = &r->remap;
 
 
-                for (ic = 0; ic < r->i_ss.channels; ic++) {
-
-                    if (r->map_table[oc][ic] <= 0.0)
-                        continue;
-
-                    if (r->map_table[oc][ic] >= 1.0) {
-                        static const int16_t one = 1;
-
-                        oil_vectoradd_s16(
-                                (int16_t*) dst + oc, o_skip,
-                                (int16_t*) dst + oc, o_skip,
-                                (int16_t*) src + ic, i_skip,
-                                (int) n_frames,
-                                &one, &one);
-
-                    } else
-
-                        vectoradd_s16_with_fraction(
-                                (int16_t*) dst + oc, o_skip,
-                                (int16_t*) dst + oc, o_skip,
-                                (int16_t*) src + ic, i_skip,
-                                (int) n_frames,
-                                1.0f, r->map_table[oc][ic]);
-                }
-            }
-
-            break;
-
-        default:
-            pa_assert_not_reached();
-    }
+    pa_assert(remap->do_remap);
+    remap->do_remap(remap, dst, src, n_frames);
 
     pa_memblock_release(input->memblock);
     pa_memblock_release(r->buf2.memblock);
 
 
     pa_memblock_release(input->memblock);
     pa_memblock_release(r->buf2.memblock);
 
-    r->buf2.length = out_n_samples * r->w_sz;
-
     return &r->buf2;
 }
 
     return &r->buf2;
 }
 
@@ -1445,9 +1391,9 @@ static void trivial_resample(pa_resampler *r, const pa_memchunk *input, unsigned
         if (j >= in_n_frames)
             break;
 
         if (j >= in_n_frames)
             break;
 
-        pa_assert(o_index * fz < pa_memblock_get_length(output->memblock));
+        pa_assert_fp(o_index * fz < pa_memblock_get_length(output->memblock));
 
 
-        oil_memcpy((uint8_t*) dst + fz * o_index,
+        memcpy((uint8_t*) dst + fz * o_index,
                    (uint8_t*) src + fz * j, (int) fz);
     }
 
                    (uint8_t*) src + fz * j, (int) fz);
     }