4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include <samplerate.h>
32 #include <liboil/liboilfuncs.h>
33 #include <liboil/liboil.h>
35 #include <pulse/xmalloc.h>
36 #include <pulsecore/sconv.h>
37 #include <pulsecore/log.h>
38 #include <pulsecore/macro.h>
40 #include "speexwrap.h"
42 #include "resampler.h"
45 pa_resample_method_t resample_method
;
46 pa_sample_spec i_ss
, o_ss
;
47 pa_channel_map i_cm
, o_cm
;
48 size_t i_fz
, o_fz
, w_sz
;
51 pa_memchunk buf1
, buf2
, buf3
, buf4
;
52 unsigned buf1_samples
, buf2_samples
, buf3_samples
, buf4_samples
;
54 pa_sample_format_t work_format
;
56 pa_convert_func_t to_work_format_func
;
57 pa_convert_func_t from_work_format_func
;
59 int map_table
[PA_CHANNELS_MAX
][PA_CHANNELS_MAX
];
62 void (*impl_free
)(pa_resampler
*r
);
63 void (*impl_update_rates
)(pa_resampler
*r
);
64 void (*impl_resample
)(pa_resampler
*r
, const pa_memchunk
*in
, unsigned in_samples
, pa_memchunk
*out
, unsigned *out_samples
);
66 struct { /* data specific to the trivial resampler */
71 struct { /* data specific to libsamplerate */
75 struct { /* data specific to speex */
76 SpeexResamplerState
* state
;
80 static int libsamplerate_init(pa_resampler
*r
);
81 static int trivial_init(pa_resampler
*r
);
82 static int speex_init(pa_resampler
*r
);
84 static void calc_map_table(pa_resampler
*r
);
86 static int (* const init_table
[])(pa_resampler
*r
) = {
87 [PA_RESAMPLER_SRC_SINC_BEST_QUALITY
] = libsamplerate_init
,
88 [PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY
] = libsamplerate_init
,
89 [PA_RESAMPLER_SRC_SINC_FASTEST
] = libsamplerate_init
,
90 [PA_RESAMPLER_SRC_ZERO_ORDER_HOLD
] = libsamplerate_init
,
91 [PA_RESAMPLER_SRC_LINEAR
] = libsamplerate_init
,
92 [PA_RESAMPLER_TRIVIAL
] = trivial_init
,
93 [PA_RESAMPLER_SPEEX_FLOAT_BASE
+0] = speex_init
,
94 [PA_RESAMPLER_SPEEX_FLOAT_BASE
+1] = speex_init
,
95 [PA_RESAMPLER_SPEEX_FLOAT_BASE
+2] = speex_init
,
96 [PA_RESAMPLER_SPEEX_FLOAT_BASE
+3] = speex_init
,
97 [PA_RESAMPLER_SPEEX_FLOAT_BASE
+4] = speex_init
,
98 [PA_RESAMPLER_SPEEX_FLOAT_BASE
+5] = speex_init
,
99 [PA_RESAMPLER_SPEEX_FLOAT_BASE
+6] = speex_init
,
100 [PA_RESAMPLER_SPEEX_FLOAT_BASE
+7] = speex_init
,
101 [PA_RESAMPLER_SPEEX_FLOAT_BASE
+8] = speex_init
,
102 [PA_RESAMPLER_SPEEX_FLOAT_BASE
+9] = speex_init
,
103 [PA_RESAMPLER_SPEEX_FLOAT_BASE
+10] = speex_init
,
104 [PA_RESAMPLER_SPEEX_FIXED_BASE
+0] = speex_init
,
105 [PA_RESAMPLER_SPEEX_FIXED_BASE
+1] = speex_init
,
106 [PA_RESAMPLER_SPEEX_FIXED_BASE
+2] = speex_init
,
107 [PA_RESAMPLER_SPEEX_FIXED_BASE
+3] = speex_init
,
108 [PA_RESAMPLER_SPEEX_FIXED_BASE
+4] = speex_init
,
109 [PA_RESAMPLER_SPEEX_FIXED_BASE
+5] = speex_init
,
110 [PA_RESAMPLER_SPEEX_FIXED_BASE
+6] = speex_init
,
111 [PA_RESAMPLER_SPEEX_FIXED_BASE
+7] = speex_init
,
112 [PA_RESAMPLER_SPEEX_FIXED_BASE
+8] = speex_init
,
113 [PA_RESAMPLER_SPEEX_FIXED_BASE
+9] = speex_init
,
114 [PA_RESAMPLER_SPEEX_FIXED_BASE
+10] = speex_init
,
115 [PA_RESAMPLER_AUTO
] = NULL
,
118 static inline size_t sample_size(pa_sample_format_t f
) {
119 pa_sample_spec ss
= {
125 return pa_sample_size(&ss
);
128 pa_resampler
* pa_resampler_new(
130 const pa_sample_spec
*a
,
131 const pa_channel_map
*am
,
132 const pa_sample_spec
*b
,
133 const pa_channel_map
*bm
,
134 pa_resample_method_t resample_method
) {
136 pa_resampler
*r
= NULL
;
141 pa_assert(pa_sample_spec_valid(a
));
142 pa_assert(pa_sample_spec_valid(b
));
143 pa_assert(resample_method
>= 0);
144 pa_assert(resample_method
< PA_RESAMPLER_MAX
);
147 if (resample_method
== PA_RESAMPLER_AUTO
) {
148 if (a
->format
== PA_SAMPLE_FLOAT32LE
|| a
->format
== PA_SAMPLE_FLOAT32BE
||
149 b
->format
== PA_SAMPLE_FLOAT32LE
|| b
->format
== PA_SAMPLE_FLOAT32BE
)
150 resample_method
= PA_RESAMPLER_SPEEX_FLOAT_BASE
+ 0;
152 resample_method
= PA_RESAMPLER_SPEEX_FIXED_BASE
+ 0;
155 r
= pa_xnew(pa_resampler
, 1);
157 r
->resample_method
= resample_method
;
160 r
->impl_update_rates
= NULL
;
161 r
->impl_resample
= NULL
;
163 /* Fill sample specs */
170 pa_channel_map_init_auto(&r
->i_cm
, r
->i_ss
.channels
, PA_CHANNEL_MAP_DEFAULT
);
175 pa_channel_map_init_auto(&r
->o_cm
, r
->o_ss
.channels
, PA_CHANNEL_MAP_DEFAULT
);
177 r
->i_fz
= pa_frame_size(a
);
178 r
->o_fz
= pa_frame_size(b
);
180 pa_memchunk_reset(&r
->buf1
);
181 pa_memchunk_reset(&r
->buf2
);
182 pa_memchunk_reset(&r
->buf3
);
183 pa_memchunk_reset(&r
->buf4
);
185 r
->buf1_samples
= r
->buf2_samples
= r
->buf3_samples
= r
->buf4_samples
= 0;
189 pa_log_info("Using resampler '%s'", pa_resample_method_to_string(resample_method
));
191 if (resample_method
>= PA_RESAMPLER_SPEEX_FIXED_BASE
&& resample_method
<= PA_RESAMPLER_SPEEX_FIXED_MAX
)
192 r
->work_format
= PA_SAMPLE_S16NE
;
193 else if (resample_method
== PA_RESAMPLER_TRIVIAL
) {
195 if (r
->map_required
|| a
->format
!= b
->format
) {
197 if (a
->format
== PA_SAMPLE_FLOAT32NE
|| a
->format
== PA_SAMPLE_FLOAT32RE
)
198 r
->work_format
= PA_SAMPLE_FLOAT32NE
;
200 r
->work_format
= PA_SAMPLE_S16NE
;
203 r
->work_format
= a
->format
;
206 r
->work_format
= PA_SAMPLE_FLOAT32NE
;
208 r
->w_sz
= sample_size(r
->work_format
);
210 if (r
->i_ss
.format
== r
->work_format
)
211 r
->to_work_format_func
= NULL
;
212 else if (r
->work_format
== PA_SAMPLE_FLOAT32NE
) {
213 if (!(r
->to_work_format_func
= pa_get_convert_to_float32ne_function(r
->i_ss
.format
)))
216 pa_assert(r
->work_format
== PA_SAMPLE_S16NE
);
217 if (!(r
->to_work_format_func
= pa_get_convert_to_s16ne_function(r
->i_ss
.format
)))
221 if (r
->o_ss
.format
== r
->work_format
)
222 r
->from_work_format_func
= NULL
;
223 else if (r
->work_format
== PA_SAMPLE_FLOAT32NE
) {
224 if (!(r
->from_work_format_func
= pa_get_convert_from_float32ne_function(r
->o_ss
.format
)))
227 pa_assert(r
->work_format
== PA_SAMPLE_S16NE
);
228 if (!(r
->from_work_format_func
= pa_get_convert_from_s16ne_function(r
->o_ss
.format
)))
232 /* initialize implementation */
233 if (init_table
[resample_method
](r
) < 0)
245 void pa_resampler_free(pa_resampler
*r
) {
251 if (r
->buf1
.memblock
)
252 pa_memblock_unref(r
->buf1
.memblock
);
253 if (r
->buf2
.memblock
)
254 pa_memblock_unref(r
->buf2
.memblock
);
255 if (r
->buf3
.memblock
)
256 pa_memblock_unref(r
->buf3
.memblock
);
257 if (r
->buf4
.memblock
)
258 pa_memblock_unref(r
->buf4
.memblock
);
263 void pa_resampler_set_input_rate(pa_resampler
*r
, uint32_t rate
) {
267 if (r
->i_ss
.rate
== rate
)
271 r
->impl_update_rates(r
);
274 void pa_resampler_set_output_rate(pa_resampler
*r
, uint32_t rate
) {
278 if (r
->o_ss
.rate
== rate
)
282 r
->impl_update_rates(r
);
285 size_t pa_resampler_request(pa_resampler
*r
, size_t out_length
) {
288 return (((out_length
/ r
->o_fz
)*r
->i_ss
.rate
)/r
->o_ss
.rate
) * r
->i_fz
;
291 pa_resample_method_t
pa_resampler_get_method(pa_resampler
*r
) {
294 return r
->resample_method
;
297 static const char * const resample_methods
[] = {
298 "src-sinc-best-quality",
299 "src-sinc-medium-quality",
301 "src-zero-order-hold",
329 const char *pa_resample_method_to_string(pa_resample_method_t m
) {
331 if (m
< 0 || m
>= PA_RESAMPLER_MAX
)
334 return resample_methods
[m
];
337 pa_resample_method_t
pa_parse_resample_method(const char *string
) {
338 pa_resample_method_t m
;
342 for (m
= 0; m
< PA_RESAMPLER_MAX
; m
++)
343 if (!strcmp(string
, resample_methods
[m
]))
346 if (!strcmp(string
, "speex-fixed"))
347 return PA_RESAMPLER_SPEEX_FIXED_BASE
+ 0;
349 if (!strcmp(string
, "speex-float"))
350 return PA_RESAMPLER_SPEEX_FLOAT_BASE
+ 0;
352 return PA_RESAMPLER_INVALID
;
355 static void calc_map_table(pa_resampler
*r
) {
360 if (!(r
->map_required
= (r
->i_ss
.channels
!= r
->o_ss
.channels
|| !pa_channel_map_equal(&r
->i_cm
, &r
->o_cm
))))
363 for (oc
= 0; oc
< r
->o_ss
.channels
; oc
++) {
366 for (ic
= 0; ic
< r
->i_ss
.channels
; ic
++) {
367 pa_channel_position_t a
, b
;
373 (a
== PA_CHANNEL_POSITION_MONO
&& b
== PA_CHANNEL_POSITION_LEFT
) ||
374 (a
== PA_CHANNEL_POSITION_MONO
&& b
== PA_CHANNEL_POSITION_RIGHT
) ||
375 (a
== PA_CHANNEL_POSITION_LEFT
&& b
== PA_CHANNEL_POSITION_MONO
) ||
376 (a
== PA_CHANNEL_POSITION_RIGHT
&& b
== PA_CHANNEL_POSITION_MONO
))
378 r
->map_table
[oc
][i
++] = ic
;
381 /* Add an end marker */
382 if (i
< PA_CHANNELS_MAX
)
383 r
->map_table
[oc
][i
] = -1;
387 static pa_memchunk
* convert_to_work_format(pa_resampler
*r
, pa_memchunk
*input
) {
393 pa_assert(input
->memblock
);
395 /* Convert the incoming sample into the work sample format and place them in buf1 */
397 if (!r
->to_work_format_func
|| !input
->length
)
400 n_samples
= (input
->length
/ r
->i_fz
) * r
->i_ss
.channels
;
403 r
->buf1
.length
= r
->w_sz
* n_samples
;
405 if (!r
->buf1
.memblock
|| r
->buf1_samples
< n_samples
) {
406 if (r
->buf1
.memblock
)
407 pa_memblock_unref(r
->buf1
.memblock
);
409 r
->buf1_samples
= n_samples
;
410 r
->buf1
.memblock
= pa_memblock_new(r
->mempool
, r
->buf1
.length
);
413 src
= (uint8_t*) pa_memblock_acquire(input
->memblock
) + input
->index
;
414 dst
= (uint8_t*) pa_memblock_acquire(r
->buf1
.memblock
);
416 r
->to_work_format_func(n_samples
, src
, dst
);
418 pa_memblock_release(input
->memblock
);
419 pa_memblock_release(r
->buf1
.memblock
);
424 static pa_memchunk
*remap_channels(pa_resampler
*r
, pa_memchunk
*input
) {
425 unsigned in_n_samples
, out_n_samples
, n_frames
;
432 pa_assert(input
->memblock
);
434 /* Remap channels and place the result int buf2 */
436 if (!r
->map_required
|| !input
->length
)
439 in_n_samples
= input
->length
/ r
->w_sz
;
440 n_frames
= in_n_samples
/ r
->i_ss
.channels
;
441 out_n_samples
= n_frames
* r
->o_ss
.channels
;
444 r
->buf2
.length
= r
->w_sz
* out_n_samples
;
446 if (!r
->buf2
.memblock
|| r
->buf2_samples
< out_n_samples
) {
447 if (r
->buf2
.memblock
)
448 pa_memblock_unref(r
->buf2
.memblock
);
450 r
->buf2_samples
= out_n_samples
;
451 r
->buf2
.memblock
= pa_memblock_new(r
->mempool
, r
->buf2
.length
);
454 src
= ((uint8_t*) pa_memblock_acquire(input
->memblock
) + input
->index
);
455 dst
= pa_memblock_acquire(r
->buf2
.memblock
);
457 memset(dst
, 0, r
->buf2
.length
);
459 o_skip
= r
->w_sz
* r
->o_ss
.channels
;
460 i_skip
= r
->w_sz
* r
->i_ss
.channels
;
462 switch (r
->work_format
) {
463 case PA_SAMPLE_FLOAT32NE
:
465 for (oc
= 0; oc
< r
->o_ss
.channels
; oc
++) {
467 static const float one
= 1.0;
469 for (i
= 0; i
< PA_CHANNELS_MAX
&& r
->map_table
[oc
][i
] >= 0; i
++)
471 (float*) dst
+ oc
, o_skip
,
472 (float*) dst
+ oc
, o_skip
,
473 (float*) src
+ r
->map_table
[oc
][i
], i_skip
,
480 case PA_SAMPLE_S16NE
:
482 for (oc
= 0; oc
< r
->o_ss
.channels
; oc
++) {
484 static const int16_t one
= 1;
486 for (i
= 0; i
< PA_CHANNELS_MAX
&& r
->map_table
[oc
][i
] >= 0; i
++)
488 (int16_t*) dst
+ oc
, o_skip
,
489 (int16_t*) dst
+ oc
, o_skip
,
490 (int16_t*) src
+ r
->map_table
[oc
][i
], i_skip
,
498 pa_assert_not_reached();
501 pa_memblock_release(input
->memblock
);
502 pa_memblock_release(r
->buf2
.memblock
);
504 r
->buf2
.length
= out_n_samples
* r
->w_sz
;
509 static pa_memchunk
*resample(pa_resampler
*r
, pa_memchunk
*input
) {
510 unsigned in_n_frames
, in_n_samples
;
511 unsigned out_n_frames
, out_n_samples
;
516 /* Resample the data and place the result in buf3 */
518 if (!r
->impl_resample
|| !input
->length
)
521 in_n_samples
= input
->length
/ r
->w_sz
;
522 in_n_frames
= in_n_samples
/ r
->o_ss
.channels
;
524 out_n_frames
= ((in_n_frames
*r
->o_ss
.rate
)/r
->i_ss
.rate
)+1024;
525 out_n_samples
= out_n_frames
* r
->o_ss
.channels
;
528 r
->buf3
.length
= r
->w_sz
* out_n_samples
;
530 if (!r
->buf3
.memblock
|| r
->buf3_samples
< out_n_samples
) {
531 if (r
->buf3
.memblock
)
532 pa_memblock_unref(r
->buf3
.memblock
);
534 r
->buf3_samples
= out_n_samples
;
535 r
->buf3
.memblock
= pa_memblock_new(r
->mempool
, r
->buf3
.length
);
538 r
->impl_resample(r
, input
, in_n_frames
, &r
->buf3
, &out_n_frames
);
539 r
->buf3
.length
= out_n_frames
* r
->w_sz
* r
->o_ss
.channels
;
544 static pa_memchunk
*convert_from_work_format(pa_resampler
*r
, pa_memchunk
*input
) {
545 unsigned n_samples
, n_frames
;
551 /* Convert the data into the correct sample type and place the result in buf4 */
553 if (!r
->from_work_format_func
|| !input
->length
)
556 n_samples
= input
->length
/ r
->w_sz
;
557 n_frames
= n_samples
/ r
->o_ss
.channels
;
560 r
->buf4
.length
= r
->o_fz
* n_frames
;
562 if (!r
->buf4
.memblock
|| r
->buf4_samples
< n_samples
) {
563 if (r
->buf4
.memblock
)
564 pa_memblock_unref(r
->buf4
.memblock
);
566 r
->buf4_samples
= n_samples
;
567 r
->buf4
.memblock
= pa_memblock_new(r
->mempool
, r
->buf4
.length
);
570 src
= (uint8_t*) pa_memblock_acquire(input
->memblock
) + input
->index
;
571 dst
= pa_memblock_acquire(r
->buf4
.memblock
);
572 r
->from_work_format_func(n_samples
, src
, dst
);
573 pa_memblock_release(input
->memblock
);
574 pa_memblock_release(r
->buf4
.memblock
);
576 r
->buf4
.length
= r
->o_fz
* n_frames
;
581 void pa_resampler_run(pa_resampler
*r
, const pa_memchunk
*in
, pa_memchunk
*out
) {
587 pa_assert(in
->length
);
588 pa_assert(in
->memblock
);
589 pa_assert(in
->length
% r
->i_fz
== 0);
591 buf
= (pa_memchunk
*) in
;
592 buf
= convert_to_work_format(r
, buf
);
593 buf
= remap_channels(r
, buf
);
594 buf
= resample(r
, buf
);
597 buf
= convert_from_work_format(r
, buf
);
601 pa_memblock_ref(buf
->memblock
);
603 pa_memchunk_reset(buf
);
605 pa_memchunk_reset(out
);
608 /*** libsamplerate based implementation ***/
610 static void libsamplerate_resample(pa_resampler
*r
, const pa_memchunk
*input
, unsigned in_n_frames
, pa_memchunk
*output
, unsigned *out_n_frames
) {
616 pa_assert(out_n_frames
);
618 memset(&data
, 0, sizeof(data
));
620 data
.data_in
= (float*) ((uint8_t*) pa_memblock_acquire(input
->memblock
) + input
->index
);
621 data
.input_frames
= in_n_frames
;
623 data
.data_out
= (float*) ((uint8_t*) pa_memblock_acquire(output
->memblock
) + output
->index
);
624 data
.output_frames
= *out_n_frames
;
626 data
.src_ratio
= (double) r
->o_ss
.rate
/ r
->i_ss
.rate
;
627 data
.end_of_input
= 0;
629 pa_assert_se(src_process(r
->src
.state
, &data
) == 0);
630 pa_assert((unsigned) data
.input_frames_used
== in_n_frames
);
632 pa_memblock_release(input
->memblock
);
633 pa_memblock_release(output
->memblock
);
635 *out_n_frames
= data
.output_frames_gen
;
638 static void libsamplerate_update_rates(pa_resampler
*r
) {
641 pa_assert_se(src_set_ratio(r
->src
.state
, (double) r
->o_ss
.rate
/ r
->i_ss
.rate
) == 0);
644 static void libsamplerate_free(pa_resampler
*r
) {
648 src_delete(r
->src
.state
);
651 static int libsamplerate_init(pa_resampler
*r
) {
656 if (!(r
->src
.state
= src_new(r
->resample_method
, r
->o_ss
.channels
, &err
)))
659 r
->impl_free
= libsamplerate_free
;
660 r
->impl_update_rates
= libsamplerate_update_rates
;
661 r
->impl_resample
= libsamplerate_resample
;
666 /*** speex based implementation ***/
668 static void speex_resample_float(pa_resampler
*r
, const pa_memchunk
*input
, unsigned in_n_frames
, pa_memchunk
*output
, unsigned *out_n_frames
) {
670 uint32_t inf
= in_n_frames
, outf
= *out_n_frames
;
675 pa_assert(out_n_frames
);
677 in
= (float*) ((uint8_t*) pa_memblock_acquire(input
->memblock
) + input
->index
);
678 out
= (float*) ((uint8_t*) pa_memblock_acquire(output
->memblock
) + output
->index
);
680 pa_assert_se(paspfl_resampler_process_interleaved_float(r
->speex
.state
, in
, &inf
, out
, &outf
) == 0);
682 pa_memblock_release(input
->memblock
);
683 pa_memblock_release(output
->memblock
);
685 pa_assert(inf
== in_n_frames
);
686 *out_n_frames
= outf
;
689 static void speex_resample_int(pa_resampler
*r
, const pa_memchunk
*input
, unsigned in_n_frames
, pa_memchunk
*output
, unsigned *out_n_frames
) {
691 uint32_t inf
= in_n_frames
, outf
= *out_n_frames
;
696 pa_assert(out_n_frames
);
698 in
= (int16_t*) ((uint8_t*) pa_memblock_acquire(input
->memblock
) + input
->index
);
699 out
= (int16_t*) ((uint8_t*) pa_memblock_acquire(output
->memblock
) + output
->index
);
701 pa_assert_se(paspfx_resampler_process_interleaved_int(r
->speex
.state
, in
, &inf
, out
, &outf
) == 0);
703 pa_memblock_release(input
->memblock
);
704 pa_memblock_release(output
->memblock
);
706 pa_assert(inf
== in_n_frames
);
707 *out_n_frames
= outf
;
710 static void speex_update_rates(pa_resampler
*r
) {
713 if (r
->resample_method
>= PA_RESAMPLER_SPEEX_FIXED_BASE
&& r
->resample_method
<= PA_RESAMPLER_SPEEX_FIXED_MAX
)
714 pa_assert_se(paspfx_resampler_set_rate(r
->speex
.state
, r
->i_ss
.rate
, r
->o_ss
.rate
) == 0);
716 pa_assert(r
->resample_method
>= PA_RESAMPLER_SPEEX_FLOAT_BASE
&& r
->resample_method
<= PA_RESAMPLER_SPEEX_FLOAT_MAX
);
717 pa_assert_se(paspfl_resampler_set_rate(r
->speex
.state
, r
->i_ss
.rate
, r
->o_ss
.rate
) == 0);
721 static void speex_free(pa_resampler
*r
) {
724 if (r
->speex
.state
) {
725 if (r
->resample_method
>= PA_RESAMPLER_SPEEX_FIXED_BASE
&& r
->resample_method
<= PA_RESAMPLER_SPEEX_FIXED_MAX
)
726 paspfx_resampler_destroy(r
->speex
.state
);
728 pa_assert(r
->resample_method
>= PA_RESAMPLER_SPEEX_FLOAT_BASE
&& r
->resample_method
<= PA_RESAMPLER_SPEEX_FLOAT_MAX
);
729 paspfl_resampler_destroy(r
->speex
.state
);
734 static int speex_init(pa_resampler
*r
) {
739 r
->impl_free
= speex_free
;
740 r
->impl_update_rates
= speex_update_rates
;
742 if (r
->resample_method
>= PA_RESAMPLER_SPEEX_FIXED_BASE
&& r
->resample_method
<= PA_RESAMPLER_SPEEX_FIXED_MAX
) {
743 q
= r
->resample_method
- PA_RESAMPLER_SPEEX_FIXED_BASE
;
744 r
->impl_resample
= speex_resample_int
;
746 if (!(r
->speex
.state
= paspfx_resampler_init(r
->o_ss
.channels
, r
->i_ss
.rate
, r
->o_ss
.rate
, q
, &err
)))
750 pa_assert(r
->resample_method
>= PA_RESAMPLER_SPEEX_FLOAT_BASE
&& r
->resample_method
<= PA_RESAMPLER_SPEEX_FLOAT_MAX
);
751 q
= r
->resample_method
- PA_RESAMPLER_SPEEX_FLOAT_BASE
;
752 r
->impl_resample
= speex_resample_float
;
754 if (!(r
->speex
.state
= paspfl_resampler_init(r
->o_ss
.channels
, r
->i_ss
.rate
, r
->o_ss
.rate
, q
, &err
)))
762 /* Trivial implementation */
764 static void trivial_resample(pa_resampler
*r
, const pa_memchunk
*input
, unsigned in_n_frames
, pa_memchunk
*output
, unsigned *out_n_frames
) {
772 pa_assert(out_n_frames
);
774 fz
= r
->w_sz
* r
->o_ss
.channels
;
776 src
= (uint8_t*) pa_memblock_acquire(input
->memblock
) + input
->index
;
777 dst
= (uint8_t*) pa_memblock_acquire(output
->memblock
) + output
->index
;
779 for (o_index
= 0;; o_index
++, r
->trivial
.o_counter
++) {
782 j
= ((r
->trivial
.o_counter
* r
->i_ss
.rate
) / r
->o_ss
.rate
);
783 j
= j
> r
->trivial
.i_counter
? j
- r
->trivial
.i_counter
: 0;
785 if (j
>= in_n_frames
)
788 pa_assert(o_index
* fz
< pa_memblock_get_length(output
->memblock
));
790 oil_memcpy((uint8_t*) dst
+ fz
* o_index
,
791 (uint8_t*) src
+ fz
* j
, fz
);
794 pa_memblock_release(input
->memblock
);
795 pa_memblock_release(output
->memblock
);
797 *out_n_frames
= o_index
;
799 r
->trivial
.i_counter
+= in_n_frames
;
801 /* Normalize counters */
802 while (r
->trivial
.i_counter
>= r
->i_ss
.rate
) {
803 pa_assert(r
->trivial
.o_counter
>= r
->o_ss
.rate
);
805 r
->trivial
.i_counter
-= r
->i_ss
.rate
;
806 r
->trivial
.o_counter
-= r
->o_ss
.rate
;
810 static void trivial_update_rates(pa_resampler
*r
) {
813 r
->trivial
.i_counter
= 0;
814 r
->trivial
.o_counter
= 0;
817 static int trivial_init(pa_resampler
*r
) {
820 r
->trivial
.o_counter
= r
->trivial
.i_counter
= 0;
822 r
->impl_resample
= trivial_resample
;
823 r
->impl_update_rates
= trivial_update_rates
;