2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "pcm_resample_internal.h"
31 #define G_LOG_DOMAIN "pcm"
34 libsamplerate_quark(void)
36 return g_quark_from_static_string("libsamplerate");
40 pcm_resample_lsr_deinit(struct pcm_resample_state
*state
)
42 if (state
->state
!= NULL
)
43 state
->state
= src_delete(state
->state
);
45 pcm_buffer_deinit(&state
->in
);
46 pcm_buffer_deinit(&state
->out
);
47 pcm_buffer_deinit(&state
->buffer
);
50 static int pcm_resample_get_converter(void)
52 const char *conf
= config_get_string(CONF_SAMPLERATE_CONVERTER
, NULL
);
59 convalgo
= SRC_SINC_FASTEST
;
63 convalgo
= strtol(conf
, &test
, 10);
64 if (*test
== '\0' && src_get_name(convalgo
))
68 for (convalgo
= 0 ; ; convalgo
++) {
69 test2
= src_get_name(convalgo
);
71 convalgo
= SRC_SINC_FASTEST
;
74 if (g_ascii_strncasecmp(test2
, conf
, len
) == 0)
78 g_warning("unknown samplerate converter \"%s\"", conf
);
80 g_debug("selecting samplerate converter \"%s\"",
81 src_get_name(convalgo
));
87 pcm_resample_set(struct pcm_resample_state
*state
,
88 uint8_t channels
, unsigned src_rate
, unsigned dest_rate
,
91 static int convalgo
= -1;
93 SRC_DATA
*data
= &state
->data
;
96 convalgo
= pcm_resample_get_converter();
98 /* (re)set the state/ratio if the in or out format changed */
99 if (channels
== state
->prev
.channels
&&
100 src_rate
== state
->prev
.src_rate
&&
101 dest_rate
== state
->prev
.dest_rate
)
105 state
->prev
.channels
= channels
;
106 state
->prev
.src_rate
= src_rate
;
107 state
->prev
.dest_rate
= dest_rate
;
110 state
->state
= src_delete(state
->state
);
112 state
->state
= src_new(convalgo
, channels
, &error
);
114 g_set_error(error_r
, libsamplerate_quark(), state
->error
,
115 "libsamplerate initialization has failed: %s",
116 src_strerror(error
));
120 data
->src_ratio
= (double)dest_rate
/ (double)src_rate
;
121 g_debug("setting samplerate conversion ratio to %.2lf",
123 src_set_ratio(state
->state
, data
->src_ratio
);
129 pcm_resample_lsr_16(struct pcm_resample_state
*state
,
132 const int16_t *src_buffer
, size_t src_size
,
133 unsigned dest_rate
, size_t *dest_size_r
,
137 SRC_DATA
*data
= &state
->data
;
139 size_t data_out_size
;
141 int16_t *dest_buffer
;
143 assert((src_size
% (sizeof(*src_buffer
) * channels
)) == 0);
145 success
= pcm_resample_set(state
, channels
, src_rate
, dest_rate
,
150 /* there was an error previously, and nothing has changed */
152 g_set_error(error_r
, libsamplerate_quark(), state
->error
,
153 "libsamplerate has failed: %s",
154 src_strerror(state
->error
));
158 data
->input_frames
= src_size
/ sizeof(*src_buffer
) / channels
;
159 data_in_size
= data
->input_frames
* sizeof(float) * channels
;
160 data
->data_in
= pcm_buffer_get(&state
->in
, data_in_size
);
162 data
->output_frames
= (src_size
* dest_rate
+ src_rate
- 1) / src_rate
;
163 data_out_size
= data
->output_frames
* sizeof(float) * channels
;
164 data
->data_out
= pcm_buffer_get(&state
->out
, data_out_size
);
166 src_short_to_float_array(src_buffer
, data
->data_in
,
167 data
->input_frames
* channels
);
169 error
= src_process(state
->state
, data
);
171 g_set_error(error_r
, libsamplerate_quark(), error
,
172 "libsamplerate has failed: %s",
173 src_strerror(error
));
174 state
->error
= error
;
178 *dest_size_r
= data
->output_frames_gen
*
179 sizeof(*dest_buffer
) * channels
;
180 dest_buffer
= pcm_buffer_get(&state
->buffer
, *dest_size_r
);
181 src_float_to_short_array(data
->data_out
, dest_buffer
,
182 data
->output_frames_gen
* channels
);
187 #ifdef HAVE_LIBSAMPLERATE_NOINT
189 /* libsamplerate introduced these functions in v0.1.3 */
192 src_int_to_float_array(const int *in
, float *out
, int len
)
195 *out
++ = *in
++ / (float)(1 << (24 - 1));
199 src_float_to_int_array (const float *in
, int *out
, int len
)
202 *out
++ = *in
++ * (float)(1 << (24 - 1));
208 pcm_resample_lsr_32(struct pcm_resample_state
*state
,
211 const int32_t *src_buffer
, size_t src_size
,
212 unsigned dest_rate
, size_t *dest_size_r
,
216 SRC_DATA
*data
= &state
->data
;
218 size_t data_out_size
;
220 int32_t *dest_buffer
;
222 assert((src_size
% (sizeof(*src_buffer
) * channels
)) == 0);
224 success
= pcm_resample_set(state
, channels
, src_rate
, dest_rate
,
229 /* there was an error previously, and nothing has changed */
231 g_set_error(error_r
, libsamplerate_quark(), state
->error
,
232 "libsamplerate has failed: %s",
233 src_strerror(state
->error
));
237 data
->input_frames
= src_size
/ sizeof(*src_buffer
) / channels
;
238 data_in_size
= data
->input_frames
* sizeof(float) * channels
;
239 data
->data_in
= pcm_buffer_get(&state
->in
, data_in_size
);
241 data
->output_frames
= (src_size
* dest_rate
+ src_rate
- 1) / src_rate
;
242 data_out_size
= data
->output_frames
* sizeof(float) * channels
;
243 data
->data_out
= pcm_buffer_get(&state
->out
, data_out_size
);
245 src_int_to_float_array(src_buffer
, data
->data_in
,
246 data
->input_frames
* channels
);
248 error
= src_process(state
->state
, data
);
250 g_set_error(error_r
, libsamplerate_quark(), error
,
251 "libsamplerate has failed: %s",
252 src_strerror(error
));
253 state
->error
= error
;
257 *dest_size_r
= data
->output_frames_gen
*
258 sizeof(*dest_buffer
) * channels
;
259 dest_buffer
= pcm_buffer_get(&state
->buffer
, *dest_size_r
);
260 src_float_to_int_array(data
->data_out
, dest_buffer
,
261 data
->output_frames_gen
* channels
);