198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/* Copyright (C) 2007-2008 Jean-Marc Valin
298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Copyright (C) 2008      Thorvald Natvig
398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   File: resample.c
598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Arbitrary resampling code
698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Redistribution and use in source and binary forms, with or without
898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   modification, are permitted provided that the following conditions are
998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   met:
1098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
1198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   1. Redistributions of source code must retain the above copyright notice,
1298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   this list of conditions and the following disclaimer.
1398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
1498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   2. Redistributions in binary form must reproduce the above copyright
1598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   notice, this list of conditions and the following disclaimer in the
1698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   documentation and/or other materials provided with the distribution.
1798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
1898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   3. The name of the author may not be used to endorse or promote products
1998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   derived from this software without specific prior written permission.
2098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
2198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   POSSIBILITY OF SUCH DAMAGE.
3298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project*/
3398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
3498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/*
3598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   The design goals of this code are:
3698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      - Very fast algorithm
3798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      - SIMD-friendly algorithm
3898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      - Low memory requirement
3998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      - Good *perceptual* quality (and not best SNR)
4098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
4198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Warning: This resampler is relatively new. Although I think I got rid of
4298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   all the major bugs and I don't expect the API to change anymore, there
4398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   may be something I've missed. So use with caution.
4498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
4598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   This algorithm is based on this original resampling algorithm:
4698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Smith, Julius O. Digital Audio Resampling Home Page
4798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Center for Computer Research in Music and Acoustics (CCRMA),
4898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Stanford University, 2007.
4998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   Web published at http://www-ccrma.stanford.edu/~jos/resample/.
5098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
5198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   There is one main difference, though. This resampler uses cubic
5298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   interpolation instead of linear interpolation in the above paper. This
5398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   makes the table much smaller and makes it possible to compute that table
5498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   on a per-stream basis. In turn, being able to tweak the table for each
5598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   stream makes it possible to both reduce complexity on simple ratios
5698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   (e.g. 2/3), and get rid of the rounding operations in the inner loop.
5798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   The latter both reduces CPU time and makes the algorithm more SIMD-friendly.
5898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project*/
5998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
6098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef HAVE_CONFIG_H
6198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "config.h"
6298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
6398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
6498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef OUTSIDE_SPEEX
6598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include <stdlib.h>
6698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic void *speex_alloc (int size) {return calloc(size,1);}
6798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);}
6898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic void speex_free (void *ptr) {free(ptr);}
6998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "speex_resampler.h"
7098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "arch.h"
7198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else /* OUTSIDE_SPEEX */
7298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
7398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "speex/speex_resampler.h"
7498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "arch.h"
7598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "os_support.h"
7698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif /* OUTSIDE_SPEEX */
7798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
7898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "stack_alloc.h"
7998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include <math.h>
8098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
8198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifndef M_PI
8298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define M_PI 3.14159263
8398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
8498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
8598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
8698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))
8798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
8898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))
8998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
9098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
9198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define IMAX(a,b) ((a) > (b) ? (a) : (b))
9298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define IMIN(a,b) ((a) < (b) ? (a) : (b))
9398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
9498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifndef NULL
9598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define NULL 0
9698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
9798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
9898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef _USE_SSE
9998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include "resample_sse.h"
10098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
10198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
1026adacb80950e35de9df0a1d7a060aba795712494Jyri Sarha#ifdef _USE_NEON
1036adacb80950e35de9df0a1d7a060aba795712494Jyri Sarha#include "resample_neon.h"
1046adacb80950e35de9df0a1d7a060aba795712494Jyri Sarha#endif
1056adacb80950e35de9df0a1d7a060aba795712494Jyri Sarha
10698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/* Numer of elements to allocate on the stack */
10798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef VAR_ARRAYS
10898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define FIXED_STACK_ALLOC 8192
10998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
11098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define FIXED_STACK_ALLOC 1024
11198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
11298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
11398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projecttypedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *);
11498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
11598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstruct SpeexResamplerState_ {
11698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t in_rate;
11798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t out_rate;
11898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t num_rate;
11998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t den_rate;
12098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
12198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int    quality;
12298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t nb_channels;
12398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t filt_len;
12498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t mem_alloc_size;
12598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t buffer_size;
12698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int          int_advance;
12798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int          frac_advance;
12898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   float  cutoff;
12998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t oversample;
13098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int          initialised;
13198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int          started;
13298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
13398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* These are per-channel */
13498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_int32_t  *last_sample;
13598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t *samp_frac_num;
13698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t *magic_samples;
13798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
13898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *mem;
13998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *sinc_table;
14098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t sinc_table_length;
14198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   resampler_basic_func resampler_ptr;
14298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
14398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int    in_stride;
14498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int    out_stride;
14598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project} ;
14698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
14798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic double kaiser12_table[68] = {
14898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076,
14998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014,
15098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601,
15198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014,
15298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490,
15398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546,
15498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178,
15598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947,
15698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058,
15798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438,
15898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734,
15998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.00001000, 0.00000000};
16098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/*
16198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic double kaiser12_table[36] = {
16298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741,
16398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762,
16498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274,
16598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466,
16698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291,
16798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000};
16898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project*/
16998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic double kaiser10_table[36] = {
17098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446,
17198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347,
17298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962,
17398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451,
17498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739,
17598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000};
17698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
17798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic double kaiser8_table[36] = {
17898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200,
17998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126,
18098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272,
18198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758,
18298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490,
18398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000};
18498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
18598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic double kaiser6_table[36] = {
18698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003,
18798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565,
18898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561,
18998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058,
19098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600,
19198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000};
19298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
19398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstruct FuncDef {
19498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   double *table;
19598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int oversample;
19698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project};
19798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
19898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic struct FuncDef _KAISER12 = {kaiser12_table, 64};
19998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define KAISER12 (&_KAISER12)
20098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/*static struct FuncDef _KAISER12 = {kaiser12_table, 32};
20198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define KAISER12 (&_KAISER12)*/
20298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic struct FuncDef _KAISER10 = {kaiser10_table, 32};
20398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define KAISER10 (&_KAISER10)
20498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic struct FuncDef _KAISER8 = {kaiser8_table, 32};
20598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define KAISER8 (&_KAISER8)
20698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic struct FuncDef _KAISER6 = {kaiser6_table, 32};
20798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#define KAISER6 (&_KAISER6)
20898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
20998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstruct QualityMapping {
21098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int base_length;
21198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int oversample;
21298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   float downsample_bandwidth;
21398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   float upsample_bandwidth;
21498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   struct FuncDef *window_func;
21598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project};
21698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
21798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
21898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/* This table maps conversion quality to internal parameters. There are two
21998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   reasons that explain why the up-sampling bandwidth is larger than the
22098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   down-sampling bandwidth:
22198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   1) When up-sampling, we can assume that the spectrum is already attenuated
22298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      close to the Nyquist rate (from an A/D or a previous resampling filter)
22398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   2) Any aliasing that occurs very close to the Nyquist rate will be masked
22498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      by the sinusoids/noise just below the Nyquist rate (guaranteed only for
22598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      up-sampling).
22698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project*/
22798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic const struct QualityMapping quality_map[11] = {
22898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {  8,  4, 0.830f, 0.860f, KAISER6 }, /* Q0 */
22998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   { 16,  4, 0.850f, 0.880f, KAISER6 }, /* Q1 */
23098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   { 32,  4, 0.882f, 0.910f, KAISER6 }, /* Q2 */  /* 82.3% cutoff ( ~60 dB stop) 6  */
23198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   { 48,  8, 0.895f, 0.917f, KAISER8 }, /* Q3 */  /* 84.9% cutoff ( ~80 dB stop) 8  */
23298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   { 64,  8, 0.921f, 0.940f, KAISER8 }, /* Q4 */  /* 88.7% cutoff ( ~80 dB stop) 8  */
23398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   { 80, 16, 0.922f, 0.940f, KAISER10}, /* Q5 */  /* 89.1% cutoff (~100 dB stop) 10 */
23498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   { 96, 16, 0.940f, 0.945f, KAISER10}, /* Q6 */  /* 91.5% cutoff (~100 dB stop) 10 */
23598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */  /* 93.1% cutoff (~100 dB stop) 10 */
23698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */  /* 94.5% cutoff (~100 dB stop) 10 */
23798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {192, 32, 0.968f, 0.968f, KAISER12}, /* Q9 */  /* 95.5% cutoff (~100 dB stop) 10 */
23898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */
23998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project};
24098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/*8,24,40,56,80,104,128,160,200,256,320*/
24198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic double compute_func(float x, struct FuncDef *func)
24298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
24398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   float y, frac;
24498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   double interp[4];
24598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int ind;
24698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   y = x*func->oversample;
24798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ind = (int)floor(y);
24898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   frac = (y-ind);
24998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* CSE with handle the repeated powers */
25098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   interp[3] =  -0.1666666667*frac + 0.1666666667*(frac*frac*frac);
25198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac);
25298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
25398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac);
25498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Just to make sure we don't have rounding problems */
25598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   interp[1] = 1.f-interp[3]-interp[2]-interp[0];
25698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
25798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /*sum = frac*accum[1] + (1-frac)*accum[2];*/
25898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3];
25998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
26098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
26198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#if 0
26298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#include <stdio.h>
26398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectint main(int argc, char **argv)
26498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
26598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int i;
26698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<256;i++)
26798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
26898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      printf ("%f\n", compute_func(i/256., KAISER12));
26998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
27098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return 0;
27198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
27298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
27398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
27498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
27598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/* The slow way of computing a sinc for the table. Should improve that some day */
27698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)
27798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
27898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /*fprintf (stderr, "%f ", x);*/
27998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   float xx = x * cutoff;
28098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (fabs(x)<1e-6f)
28198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      return WORD2INT(32768.*cutoff);
28298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   else if (fabs(x) > .5f*N)
28398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      return 0;
28498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /*FIXME: Can it really be any slower than this? */
28598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func));
28698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
28798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
28898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/* The slow way of computing a sinc for the table. Should improve that some day */
28998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)
29098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
29198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /*fprintf (stderr, "%f ", x);*/
29298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   float xx = x * cutoff;
29398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (fabs(x)<1e-6)
29498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      return cutoff;
29598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   else if (fabs(x) > .5*N)
29698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      return 0;
29798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /*FIXME: Can it really be any slower than this? */
29898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func);
29998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
30098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
30198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
30298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
30398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic void cubic_coef(spx_word16_t x, spx_word16_t interp[4])
30498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
30598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
30698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   but I know it's MMSE-optimal on a sinc */
30798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t x2, x3;
30898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   x2 = MULT16_16_P15(x, x);
30998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   x3 = MULT16_16_P15(x, x2);
31098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15);
31198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1));
31298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15);
31398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Just to make sure we don't have rounding problems */
31498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3];
31598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (interp[2]<32767)
31698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      interp[2]+=1;
31798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
31898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
31998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic void cubic_coef(spx_word16_t frac, spx_word16_t interp[4])
32098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
32198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
32298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   but I know it's MMSE-optimal on a sinc */
32398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   interp[0] =  -0.16667f*frac + 0.16667f*frac*frac*frac;
32498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac;
32598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
32698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac;
32798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Just to make sure we don't have rounding problems */
32898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   interp[2] = 1.-interp[0]-interp[1]-interp[3];
32998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
33098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
33198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
33298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
33398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
33498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int N = st->filt_len;
33598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int out_sample = 0;
33698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int last_sample = st->last_sample[channel_index];
33798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
33898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const spx_word16_t *sinc_table = st->sinc_table;
33998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int out_stride = st->out_stride;
34098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int int_advance = st->int_advance;
34198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int frac_advance = st->frac_advance;
34298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const spx_uint32_t den_rate = st->den_rate;
34398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t sum;
34498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int j;
34598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
34698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
34798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
34898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      const spx_word16_t *sinc = & sinc_table[samp_frac_num*N];
34998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      const spx_word16_t *iptr = & in[last_sample];
35098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
35198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifndef OVERRIDE_INNER_PRODUCT_SINGLE
35298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      float accum[4] = {0,0,0,0};
35398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
35498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for(j=0;j<N;j+=4) {
35598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[0] += sinc[j]*iptr[j];
35698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[1] += sinc[j+1]*iptr[j+1];
35798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[2] += sinc[j+2]*iptr[j+2];
35898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[3] += sinc[j+3]*iptr[j+3];
35998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
36098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      sum = accum[0] + accum[1] + accum[2] + accum[3];
3616adacb80950e35de9df0a1d7a060aba795712494Jyri Sarha      sum = SATURATE32PSHR(sum, 15, 32767);
36298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
36398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      sum = inner_product_single(sinc, iptr, N);
36498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
36598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
3666adacb80950e35de9df0a1d7a060aba795712494Jyri Sarha      out[out_stride * out_sample++] = sum;
36798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      last_sample += int_advance;
36898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      samp_frac_num += frac_advance;
36998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (samp_frac_num >= den_rate)
37098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
37198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         samp_frac_num -= den_rate;
37298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         last_sample++;
37398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
37498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
37598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
37698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->last_sample[channel_index] = last_sample;
37798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->samp_frac_num[channel_index] = samp_frac_num;
37898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return out_sample;
37998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
38098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
38198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
38298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
38398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/* This is the same as the previous function, except with a double-precision accumulator */
38498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
38598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
38698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int N = st->filt_len;
38798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int out_sample = 0;
38898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int last_sample = st->last_sample[channel_index];
38998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
39098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const spx_word16_t *sinc_table = st->sinc_table;
39198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int out_stride = st->out_stride;
39298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int int_advance = st->int_advance;
39398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int frac_advance = st->frac_advance;
39498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const spx_uint32_t den_rate = st->den_rate;
39598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   double sum;
39698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int j;
39798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
39898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
39998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
40098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      const spx_word16_t *sinc = & sinc_table[samp_frac_num*N];
40198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      const spx_word16_t *iptr = & in[last_sample];
40298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
40398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifndef OVERRIDE_INNER_PRODUCT_DOUBLE
40498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      double accum[4] = {0,0,0,0};
40598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
40698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for(j=0;j<N;j+=4) {
40798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[0] += sinc[j]*iptr[j];
40898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[1] += sinc[j+1]*iptr[j+1];
40998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[2] += sinc[j+2]*iptr[j+2];
41098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[3] += sinc[j+3]*iptr[j+3];
41198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
41298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      sum = accum[0] + accum[1] + accum[2] + accum[3];
41398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
41498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      sum = inner_product_double(sinc, iptr, N);
41598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
41698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
41798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      out[out_stride * out_sample++] = PSHR32(sum, 15);
41898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      last_sample += int_advance;
41998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      samp_frac_num += frac_advance;
42098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (samp_frac_num >= den_rate)
42198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
42298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         samp_frac_num -= den_rate;
42398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         last_sample++;
42498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
42598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
42698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
42798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->last_sample[channel_index] = last_sample;
42898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->samp_frac_num[channel_index] = samp_frac_num;
42998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return out_sample;
43098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
43198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
43298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
43398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
43498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
43598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int N = st->filt_len;
43698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int out_sample = 0;
43798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int last_sample = st->last_sample[channel_index];
43898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
43998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int out_stride = st->out_stride;
44098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int int_advance = st->int_advance;
44198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int frac_advance = st->frac_advance;
44298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const spx_uint32_t den_rate = st->den_rate;
44398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int j;
44498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t sum;
44598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
44698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
44798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
44898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      const spx_word16_t *iptr = & in[last_sample];
44998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
45098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      const int offset = samp_frac_num*st->oversample/st->den_rate;
45198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
45298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
45398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
45498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
45598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
45698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_word16_t interp[4];
45798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
45898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
45998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
46098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_word32_t accum[4] = {0,0,0,0};
46198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
46298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for(j=0;j<N;j++) {
46398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        const spx_word16_t curr_in=iptr[j];
46498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
46598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
46698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
46798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
46898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
46998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
47098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      cubic_coef(frac, interp);
47198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);
4726adacb80950e35de9df0a1d7a060aba795712494Jyri Sarha      sum = SATURATE32PSHR(sum, 15, 32767);
47398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
47498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      cubic_coef(frac, interp);
47598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
47698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
47798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
4786adacb80950e35de9df0a1d7a060aba795712494Jyri Sarha      out[out_stride * out_sample++] = sum;
47998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      last_sample += int_advance;
48098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      samp_frac_num += frac_advance;
48198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (samp_frac_num >= den_rate)
48298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
48398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         samp_frac_num -= den_rate;
48498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         last_sample++;
48598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
48698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
48798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
48898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->last_sample[channel_index] = last_sample;
48998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->samp_frac_num[channel_index] = samp_frac_num;
49098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return out_sample;
49198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
49298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
49398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
49498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
49598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project/* This is the same as the previous function, except with a double-precision accumulator */
49698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
49798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
49898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int N = st->filt_len;
49998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int out_sample = 0;
50098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int last_sample = st->last_sample[channel_index];
50198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
50298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int out_stride = st->out_stride;
50398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int int_advance = st->int_advance;
50498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int frac_advance = st->frac_advance;
50598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const spx_uint32_t den_rate = st->den_rate;
50698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int j;
50798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word32_t sum;
50898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
50998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
51098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
51198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      const spx_word16_t *iptr = & in[last_sample];
51298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
51398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      const int offset = samp_frac_num*st->oversample/st->den_rate;
51498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
51598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
51698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
51798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
51898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
51998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_word16_t interp[4];
52098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
52198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
52298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE
52398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      double accum[4] = {0,0,0,0};
52498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
52598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for(j=0;j<N;j++) {
52698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        const double curr_in=iptr[j];
52798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
52898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
52998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
53098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
53198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
53298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
53398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      cubic_coef(frac, interp);
53498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);
53598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
53698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      cubic_coef(frac, interp);
53798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
53898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
53998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
54098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      out[out_stride * out_sample++] = PSHR32(sum,15);
54198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      last_sample += int_advance;
54298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      samp_frac_num += frac_advance;
54398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (samp_frac_num >= den_rate)
54498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
54598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         samp_frac_num -= den_rate;
54698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         last_sample++;
54798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
54898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
54998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
55098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->last_sample[channel_index] = last_sample;
55198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->samp_frac_num[channel_index] = samp_frac_num;
55298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return out_sample;
55398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
55498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
55598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
55698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic void update_filter(SpeexResamplerState *st)
55798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
55898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t old_length;
55998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
56098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   old_length = st->filt_len;
56198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->oversample = quality_map[st->quality].oversample;
56298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->filt_len = quality_map[st->quality].base_length;
56398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
56498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->num_rate > st->den_rate)
56598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
56698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* down-sampling */
56798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate;
56898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* FIXME: divide the numerator and denominator by a certain amount if they're too large */
56998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->filt_len = st->filt_len*st->num_rate / st->den_rate;
57098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Round down to make sure we have a multiple of 4 */
57198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->filt_len &= (~0x3);
57298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (2*st->den_rate < st->num_rate)
57398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->oversample >>= 1;
57498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (4*st->den_rate < st->num_rate)
57598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->oversample >>= 1;
57698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (8*st->den_rate < st->num_rate)
57798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->oversample >>= 1;
57898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (16*st->den_rate < st->num_rate)
57998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->oversample >>= 1;
58098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (st->oversample < 1)
58198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->oversample = 1;
58298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   } else {
58398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* up-sampling */
58498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->cutoff = quality_map[st->quality].upsample_bandwidth;
58598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
58698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
58798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Choose the resampling type that requires the least amount of memory */
5886adacb80950e35de9df0a1d7a060aba795712494Jyri Sarha#ifdef RESAMPLE_FORCE_FULL_SINC_TABLE
5896adacb80950e35de9df0a1d7a060aba795712494Jyri Sarha   if (1)
5906adacb80950e35de9df0a1d7a060aba795712494Jyri Sarha#else
59198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->den_rate <= st->oversample)
5926adacb80950e35de9df0a1d7a060aba795712494Jyri Sarha#endif
59398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
59498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_uint32_t i;
59598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (!st->sinc_table)
59698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->sinc_table = (spx_word16_t *)speex_alloc(st->filt_len*st->den_rate*sizeof(spx_word16_t));
59798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      else if (st->sinc_table_length < st->filt_len*st->den_rate)
59898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
59998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,st->filt_len*st->den_rate*sizeof(spx_word16_t));
60098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->sinc_table_length = st->filt_len*st->den_rate;
60198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
60298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->den_rate;i++)
60398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
60498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         spx_int32_t j;
60598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         for (j=0;j<st->filt_len;j++)
60698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         {
60798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-(spx_int32_t)st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func);
60898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         }
60998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
61098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
61198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->resampler_ptr = resampler_basic_direct_single;
61298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
61398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (st->quality>8)
61498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->resampler_ptr = resampler_basic_direct_double;
61598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      else
61698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->resampler_ptr = resampler_basic_direct_single;
61798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
61898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/
61998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   } else {
62098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_int32_t i;
62198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (!st->sinc_table)
62298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->sinc_table = (spx_word16_t *)speex_alloc((st->filt_len*st->oversample+8)*sizeof(spx_word16_t));
62398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      else if (st->sinc_table_length < st->filt_len*st->oversample+8)
62498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
62598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,(st->filt_len*st->oversample+8)*sizeof(spx_word16_t));
62698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->sinc_table_length = st->filt_len*st->oversample+8;
62798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
62898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++)
62998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func);
63098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
63198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->resampler_ptr = resampler_basic_interpolate_single;
63298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
63398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (st->quality>8)
63498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->resampler_ptr = resampler_basic_interpolate_double;
63598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      else
63698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->resampler_ptr = resampler_basic_interpolate_single;
63798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
63898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/
63998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
64098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->int_advance = st->num_rate/st->den_rate;
64198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->frac_advance = st->num_rate%st->den_rate;
64298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
64398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
64498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Here's the place where we update the filter memory to take into account
64598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      the change in filter length. It's probably the messiest part of the code
64698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      due to handling of lots of corner cases. */
64798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (!st->mem)
64898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
64998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_uint32_t i;
65098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
65198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
65298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
65398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->mem[i] = 0;
65498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /*speex_warning("init filter");*/
65598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   } else if (!st->started)
65698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
65798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_uint32_t i;
65898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
65998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
66098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
66198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->mem[i] = 0;
66298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /*speex_warning("reinit filter");*/
66398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   } else if (st->filt_len > old_length)
66498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
66598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_int32_t i;
66698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Increase the filter length */
66798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /*speex_warning("increase filter size");*/
66898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      int old_alloc_size = st->mem_alloc_size;
66998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size)
67098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
67198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
67298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
67398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
67498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=st->nb_channels-1;i>=0;i--)
67598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
67698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         spx_int32_t j;
67798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         spx_uint32_t olen = old_length;
67898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         /*if (st->magic_samples[i])*/
67998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         {
68098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            /* Try and remove the magic samples as if nothing had happened */
68198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
68298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */
68398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            olen = old_length + 2*st->magic_samples[i];
68498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            for (j=old_length-2+st->magic_samples[i];j>=0;j--)
68598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j];
68698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            for (j=0;j<st->magic_samples[i];j++)
68798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               st->mem[i*st->mem_alloc_size+j] = 0;
68898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->magic_samples[i] = 0;
68998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         }
69098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         if (st->filt_len > olen)
69198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         {
69298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            /* If the new filter length is still bigger than the "augmented" length */
69398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            /* Copy data going backward */
69498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            for (j=0;j<olen-1;j++)
69598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)];
69698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            /* Then put zeros for lack of anything better */
69798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            for (;j<st->filt_len-1;j++)
69898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0;
69998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            /* Adjust last_sample */
70098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->last_sample[i] += (st->filt_len - olen)/2;
70198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         } else {
70298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            /* Put back some of the magic! */
70398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->magic_samples[i] = (olen - st->filt_len)/2;
70498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            for (j=0;j<st->filt_len-1+st->magic_samples[i];j++)
70598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project               st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];
70698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         }
70798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
70898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   } else if (st->filt_len < old_length)
70998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
71098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_uint32_t i;
71198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic"
71298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         samples so they can be used directly as input the next time(s) */
71398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->nb_channels;i++)
71498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
71598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         spx_uint32_t j;
71698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         spx_uint32_t old_magic = st->magic_samples[i];
71798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->magic_samples[i] = (old_length - st->filt_len)/2;
71898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         /* We must copy some of the memory that's no longer used */
71998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         /* Copy data going backward */
72098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         for (j=0;j<st->filt_len-1+st->magic_samples[i]+old_magic;j++)
72198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];
72298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->magic_samples[i] += old_magic;
72398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
72498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
72598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
72698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
72798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
72898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
72998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
73098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err);
73198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
73298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
73398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
73498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
73598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t i;
73698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   SpeexResamplerState *st;
73798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (quality > 10 || quality < 0)
73898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
73998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (err)
74098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         *err = RESAMPLER_ERR_INVALID_ARG;
74198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      return NULL;
74298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
74398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState));
74498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->initialised = 0;
74598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->started = 0;
74698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->in_rate = 0;
74798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->out_rate = 0;
74898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->num_rate = 0;
74998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->den_rate = 0;
75098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->quality = -1;
75198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->sinc_table_length = 0;
75298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->mem_alloc_size = 0;
75398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->filt_len = 0;
75498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->mem = 0;
75598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->resampler_ptr = 0;
75698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
75798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->cutoff = 1.f;
75898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->nb_channels = nb_channels;
75998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->in_stride = 1;
76098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->out_stride = 1;
76198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
76298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
76398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->buffer_size = 160;
76498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
76598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->buffer_size = 160;
76698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
76798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
76898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Per channel data */
76998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int));
77098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
77198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
77298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<nb_channels;i++)
77398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
77498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->last_sample[i] = 0;
77598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->magic_samples[i] = 0;
77698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->samp_frac_num[i] = 0;
77798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
77898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
77998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_resampler_set_quality(st, quality);
78098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate);
78198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
78298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
78398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   update_filter(st);
78498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
78598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->initialised = 1;
78698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (err)
78798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      *err = RESAMPLER_ERR_SUCCESS;
78898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
78998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return st;
79098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
79198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
79298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT void speex_resampler_destroy(SpeexResamplerState *st)
79398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
79498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->mem);
79598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->sinc_table);
79698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->last_sample);
79798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->magic_samples);
79898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st->samp_frac_num);
79998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_free(st);
80098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
80198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
80298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
80398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
80498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int j=0;
80598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int N = st->filt_len;
80698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int out_sample = 0;
80798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
80898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t ilen;
80998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
81098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->started = 1;
81198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
81298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* Call the right resampler through the function ptr */
81398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len);
81498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
81598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->last_sample[channel_index] < (spx_int32_t)*in_len)
81698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      *in_len = st->last_sample[channel_index];
81798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   *out_len = out_sample;
81898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->last_sample[channel_index] -= *in_len;
81998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
82098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ilen = *in_len;
82198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
82298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for(j=0;j<N-1;++j)
82398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     mem[j] = mem[j+ilen];
82498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
82598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return RESAMPLER_ERR_SUCCESS;
82698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
82798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
82898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Projectstatic int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_index, spx_word16_t **out, spx_uint32_t out_len) {
82998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t tmp_in_len = st->magic_samples[channel_index];
83098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
83198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int N = st->filt_len;
83298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
83398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len);
83498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
83598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->magic_samples[channel_index] -= tmp_in_len;
83698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
83798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* If we couldn't process all "magic" input samples, save the rest for next time */
83898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->magic_samples[channel_index])
83998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
84098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      spx_uint32_t i;
84198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->magic_samples[channel_index];i++)
84298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         mem[N-1+i]=mem[N-1+i+tmp_in_len];
84398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
84498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   *out += out_len*st->out_stride;
84598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return out_len;
84698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
84798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
84898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
84998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
85098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
85198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
85298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
85398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
85498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int j;
85598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t ilen = *in_len;
85698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t olen = *out_len;
85798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
85898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int filt_offs = st->filt_len - 1;
85998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const spx_uint32_t xlen = st->mem_alloc_size - filt_offs;
86098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int istride = st->in_stride;
86198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
86298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->magic_samples[channel_index])
86398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      olen -= speex_resampler_magic(st, channel_index, &out, olen);
86498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (! st->magic_samples[channel_index]) {
86598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      while (ilen && olen) {
86698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
86798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        spx_uint32_t ochunk = olen;
86898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
86998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        if (in) {
87098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project           for(j=0;j<ichunk;++j)
87198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project              x[j+filt_offs]=in[j*istride];
87298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        } else {
87398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project          for(j=0;j<ichunk;++j)
87498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            x[j+filt_offs]=0;
87598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        }
87698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        speex_resampler_process_native(st, channel_index, &ichunk, out, &ochunk);
87798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        ilen -= ichunk;
87898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        olen -= ochunk;
87998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        out += ochunk * st->out_stride;
88098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        if (in)
88198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project           in += ichunk * istride;
88298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
88398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
88498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   *in_len -= ilen;
88598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   *out_len -= olen;
88698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return RESAMPLER_ERR_SUCCESS;
88798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
88898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
88998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
89098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
89198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
89298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
89398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
89498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
89598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int j;
89698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int istride_save = st->in_stride;
89798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const int ostride_save = st->out_stride;
89898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t ilen = *in_len;
89998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t olen = *out_len;
90098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
90198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1);
90298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef VAR_ARRAYS
90398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC;
90498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   VARDECL(spx_word16_t *ystack);
90598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ALLOC(ystack, ylen, spx_word16_t);
90698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
90798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   const unsigned int ylen = FIXED_STACK_ALLOC;
90898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_word16_t ystack[FIXED_STACK_ALLOC];
90998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
91098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
91198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->out_stride = 1;
91298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
91398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   while (ilen && olen) {
91498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     spx_word16_t *y = ystack;
91598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
91698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     spx_uint32_t ochunk = (olen > ylen) ? ylen : olen;
91798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     spx_uint32_t omagic = 0;
91898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
91998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     if (st->magic_samples[channel_index]) {
92098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project       omagic = speex_resampler_magic(st, channel_index, &y, ochunk);
92198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project       ochunk -= omagic;
92298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project       olen -= omagic;
92398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     }
92498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     if (! st->magic_samples[channel_index]) {
92598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project       if (in) {
92698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         for(j=0;j<ichunk;++j)
92798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
92898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project           x[j+st->filt_len-1]=WORD2INT(in[j*istride_save]);
92998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
93098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project           x[j+st->filt_len-1]=in[j*istride_save];
93198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
93298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project       } else {
93398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         for(j=0;j<ichunk;++j)
93498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project           x[j+st->filt_len-1]=0;
93598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project       }
93698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
93798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project       speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk);
93898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     } else {
93998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project       ichunk = 0;
94098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project       ochunk = 0;
94198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     }
94298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
94398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     for (j=0;j<ochunk+omagic;++j)
94498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#ifdef FIXED_POINT
94598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        out[j*ostride_save] = ystack[j];
94698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#else
94798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project        out[j*ostride_save] = WORD2INT(ystack[j]);
94898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project#endif
94998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
95098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     ilen -= ichunk;
95198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     olen -= ochunk;
95298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     out += (ochunk+omagic) * ostride_save;
95398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project     if (in)
95498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project       in += ichunk * istride_save;
95598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
95698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->out_stride = ostride_save;
95798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   *in_len -= ilen;
95898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   *out_len -= olen;
95998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
96098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return RESAMPLER_ERR_SUCCESS;
96198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
96298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
96398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
96498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
96598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t i;
96698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int istride_save, ostride_save;
96798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t bak_len = *out_len;
96898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   istride_save = st->in_stride;
96998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ostride_save = st->out_stride;
97098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->in_stride = st->out_stride = st->nb_channels;
97198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<st->nb_channels;i++)
97298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
97398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      *out_len = bak_len;
97498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (in != NULL)
97598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len);
97698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      else
97798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         speex_resampler_process_float(st, i, NULL, in_len, out+i, out_len);
97898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
97998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->in_stride = istride_save;
98098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->out_stride = ostride_save;
98198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return RESAMPLER_ERR_SUCCESS;
98298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
98398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
98498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
98598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
98698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t i;
98798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   int istride_save, ostride_save;
98898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t bak_len = *out_len;
98998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   istride_save = st->in_stride;
99098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   ostride_save = st->out_stride;
99198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->in_stride = st->out_stride = st->nb_channels;
99298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<st->nb_channels;i++)
99398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
99498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      *out_len = bak_len;
99598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      if (in != NULL)
99698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len);
99798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      else
99898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         speex_resampler_process_int(st, i, NULL, in_len, out+i, out_len);
99998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
100098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->in_stride = istride_save;
100198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->out_stride = ostride_save;
100298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return RESAMPLER_ERR_SUCCESS;
100398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
100498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
100598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)
100698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
100798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate);
100898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
100998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
101098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate)
101198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
101298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   *in_rate = st->in_rate;
101398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   *out_rate = st->out_rate;
101498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
101598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
101698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate)
101798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
101898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t fact;
101998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t old_den;
102098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t i;
102198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den)
102298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      return RESAMPLER_ERR_SUCCESS;
102398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
102498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   old_den = st->den_rate;
102598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->in_rate = in_rate;
102698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->out_rate = out_rate;
102798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->num_rate = ratio_num;
102898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->den_rate = ratio_den;
102998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   /* FIXME: This is terribly inefficient, but who cares (at least for now)? */
103098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (fact=2;fact<=IMIN(st->num_rate, st->den_rate);fact++)
103198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
103298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0))
103398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
103498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->num_rate /= fact;
103598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->den_rate /= fact;
103698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
103798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
103898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
103998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (old_den > 0)
104098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
104198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      for (i=0;i<st->nb_channels;i++)
104298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      {
104398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         st->samp_frac_num[i]=st->samp_frac_num[i]*st->den_rate/old_den;
104498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         /* Safety net */
104598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         if (st->samp_frac_num[i] >= st->den_rate)
104698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project            st->samp_frac_num[i] = st->den_rate-1;
104798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      }
104898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
104998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
105098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->initialised)
105198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      update_filter(st);
105298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return RESAMPLER_ERR_SUCCESS;
105398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
105498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
105598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den)
105698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
105798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   *ratio_num = st->num_rate;
105898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   *ratio_den = st->den_rate;
105998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
106098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
106198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality)
106298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
106398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (quality > 10 || quality < 0)
106498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      return RESAMPLER_ERR_INVALID_ARG;
106598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->quality == quality)
106698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      return RESAMPLER_ERR_SUCCESS;
106798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->quality = quality;
106898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   if (st->initialised)
106998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      update_filter(st);
107098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return RESAMPLER_ERR_SUCCESS;
107198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
107298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
107398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)
107498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
107598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   *quality = st->quality;
107698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
107798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
107898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride)
107998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
108098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->in_stride = stride;
108198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
108298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
108398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride)
108498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
108598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   *stride = st->in_stride;
108698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
108798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
108898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride)
108998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
109098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   st->out_stride = stride;
109198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
109298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
109398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride)
109498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
109598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   *stride = st->out_stride;
109698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
109798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
109898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st)
109998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
110098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project  return st->filt_len / 2;
110198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
110298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
110398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st)
110498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
110598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project  return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate;
110698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
110798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
110898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st)
110998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
111098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t i;
111198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<st->nb_channels;i++)
111298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->last_sample[i] = st->filt_len/2;
111398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return RESAMPLER_ERR_SUCCESS;
111498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
111598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
111698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT int speex_resampler_reset_mem(SpeexResamplerState *st)
111798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
111898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   spx_uint32_t i;
111998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
112098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      st->mem[i] = 0;
112198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   return RESAMPLER_ERR_SUCCESS;
112298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
112398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project
112498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source ProjectEXPORT const char *speex_resampler_strerror(int err)
112598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project{
112698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   switch (err)
112798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   {
112898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      case RESAMPLER_ERR_SUCCESS:
112998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         return "Success.";
113098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      case RESAMPLER_ERR_ALLOC_FAILED:
113198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         return "Memory allocation failed.";
113298913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      case RESAMPLER_ERR_BAD_STATE:
113398913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         return "Bad resampler state.";
113498913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      case RESAMPLER_ERR_INVALID_ARG:
113598913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         return "Invalid argument.";
113698913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      case RESAMPLER_ERR_PTR_OVERLAP:
113798913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         return "Input and output buffers overlap.";
113898913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project      default:
113998913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project         return "Unknown error. Bad error code or strange version mismatch.";
114098913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project   }
114198913fed6520d8849fb2e246be943e04474aefaThe Android Open Source Project}
1142