• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2004-2006 Lennart Poettering
5 
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10 
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15 
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
18 ***/
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #include <speex/speex_resampler.h>
25 #include <math.h>
26 
27 #include <pulsecore/once.h>
28 #include <pulsecore/resampler.h>
29 
pa_speex_is_fixed_point(void)30 bool pa_speex_is_fixed_point(void) {
31     static bool result = false;
32     PA_ONCE_BEGIN {
33         float f_out = -1.0f, f_in = 1.0f;
34         spx_uint32_t in_len = 1, out_len = 1;
35         SpeexResamplerState *s;
36 
37         pa_assert_se(s = speex_resampler_init(1, 1, 1,
38             SPEEX_RESAMPLER_QUALITY_MIN, NULL));
39 
40         /* feed one sample that is too soft for fixed-point speex */
41         pa_assert_se(speex_resampler_process_float(s, 0, &f_in, &in_len,
42             &f_out, &out_len) == RESAMPLER_ERR_SUCCESS);
43 
44         /* expecting sample has been processed, one sample output */
45         pa_assert_se(in_len == 1 && out_len == 1);
46 
47         /* speex compiled with --enable-fixed-point will output 0.0 due to insufficient precision */
48         if (fabsf(f_out) < 0.00001f)
49             result = true;
50 
51         speex_resampler_destroy(s);
52     } PA_ONCE_END;
53     return result;
54 }
55 
56 
speex_resample_float(pa_resampler * r,const pa_memchunk * input,unsigned in_n_frames,pa_memchunk * output,unsigned * out_n_frames)57 static unsigned speex_resample_float(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
58     float *in, *out;
59     uint32_t inf = in_n_frames, outf = *out_n_frames;
60     SpeexResamplerState *state;
61 
62     pa_assert(r);
63     pa_assert(input);
64     pa_assert(output);
65     pa_assert(out_n_frames);
66 
67     state = r->impl.data;
68 
69     in = pa_memblock_acquire_chunk(input);
70     out = pa_memblock_acquire_chunk(output);
71 
72     /* Strictly speaking, speex resampler expects its input
73      * to be normalized to the [-32768.0 .. 32767.0] range.
74      * This matters if speex has been compiled with --enable-fixed-point,
75      * because such speex will round the samples to the nearest
76      * integer. speex with --enable-fixed-point is therefore incompatible
77      * with PulseAudio's floating-point sample range [-1 .. 1]. speex
78      * without --enable-fixed-point works fine with this range.
79      * Care has been taken to call speex_resample_float() only
80      * for speex compiled without --enable-fixed-point.
81      */
82     pa_assert_se(speex_resampler_process_interleaved_float(state, in, &inf, out, &outf) == 0);
83 
84     pa_memblock_release(input->memblock);
85     pa_memblock_release(output->memblock);
86 
87     pa_assert(inf == in_n_frames);
88     *out_n_frames = outf;
89 
90     return 0;
91 }
92 
speex_resample_int(pa_resampler * r,const pa_memchunk * input,unsigned in_n_frames,pa_memchunk * output,unsigned * out_n_frames)93 static unsigned speex_resample_int(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
94     int16_t *in, *out;
95     uint32_t inf = in_n_frames, outf = *out_n_frames;
96     SpeexResamplerState *state;
97 
98     pa_assert(r);
99     pa_assert(input);
100     pa_assert(output);
101     pa_assert(out_n_frames);
102 
103     state = r->impl.data;
104 
105     in = pa_memblock_acquire_chunk(input);
106     out = pa_memblock_acquire_chunk(output);
107 
108     pa_assert_se(speex_resampler_process_interleaved_int(state, in, &inf, out, &outf) == 0);
109 
110     pa_memblock_release(input->memblock);
111     pa_memblock_release(output->memblock);
112 
113     pa_assert(inf == in_n_frames);
114     *out_n_frames = outf;
115 
116     return 0;
117 }
118 
speex_update_rates(pa_resampler * r)119 static void speex_update_rates(pa_resampler *r) {
120     SpeexResamplerState *state;
121     pa_assert(r);
122 
123     state = r->impl.data;
124 
125     pa_assert_se(speex_resampler_set_rate(state, r->i_ss.rate, r->o_ss.rate) == 0);
126 }
127 
speex_reset(pa_resampler * r)128 static void speex_reset(pa_resampler *r) {
129     SpeexResamplerState *state;
130     pa_assert(r);
131 
132     state = r->impl.data;
133 
134     pa_assert_se(speex_resampler_reset_mem(state) == 0);
135 }
136 
speex_free(pa_resampler * r)137 static void speex_free(pa_resampler *r) {
138     SpeexResamplerState *state;
139     pa_assert(r);
140 
141     state = r->impl.data;
142     if (!state)
143         return;
144 
145     speex_resampler_destroy(state);
146 }
147 
pa_resampler_speex_init(pa_resampler * r)148 int pa_resampler_speex_init(pa_resampler *r) {
149     int q, err;
150     SpeexResamplerState *state;
151 
152     pa_assert(r);
153 
154     r->impl.free = speex_free;
155     r->impl.update_rates = speex_update_rates;
156     r->impl.reset = speex_reset;
157 
158     if (r->method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->method <= PA_RESAMPLER_SPEEX_FIXED_MAX) {
159 
160         q = r->method - PA_RESAMPLER_SPEEX_FIXED_BASE;
161         r->impl.resample = speex_resample_int;
162 
163     } else {
164         pa_assert(r->method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->method <= PA_RESAMPLER_SPEEX_FLOAT_MAX);
165 
166         q = r->method - PA_RESAMPLER_SPEEX_FLOAT_BASE;
167         r->impl.resample = speex_resample_float;
168     }
169 
170     pa_log_info("Choosing speex quality setting %i.", q);
171 
172     if (!(state = speex_resampler_init(r->work_channels, r->i_ss.rate, r->o_ss.rate, q, &err)))
173         return -1;
174 
175     r->impl.data = state;
176 
177     return 0;
178 }
179