configure.ac: Move OggVorbis Encoder to Encoder Plugins.
[mpd-mk.git] / src / pcm_resample_libsamplerate.c
blob99ca53da437a4047d9ccbfae5220442af88f0c5b
1 /*
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.
20 #include "config.h"
21 #include "pcm_resample_internal.h"
22 #include "conf.h"
24 #include <glib.h>
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <string.h>
30 #undef G_LOG_DOMAIN
31 #define G_LOG_DOMAIN "pcm"
33 static inline GQuark
34 libsamplerate_quark(void)
36 return g_quark_from_static_string("libsamplerate");
39 void
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);
53 long convalgo;
54 char *test;
55 const char *test2;
56 size_t len;
58 if (!conf) {
59 convalgo = SRC_SINC_FASTEST;
60 goto out;
63 convalgo = strtol(conf, &test, 10);
64 if (*test == '\0' && src_get_name(convalgo))
65 goto out;
67 len = strlen(conf);
68 for (convalgo = 0 ; ; convalgo++) {
69 test2 = src_get_name(convalgo);
70 if (!test2) {
71 convalgo = SRC_SINC_FASTEST;
72 break;
74 if (g_ascii_strncasecmp(test2, conf, len) == 0)
75 goto out;
78 g_warning("unknown samplerate converter \"%s\"", conf);
79 out:
80 g_debug("selecting samplerate converter \"%s\"",
81 src_get_name(convalgo));
83 return convalgo;
86 static bool
87 pcm_resample_set(struct pcm_resample_state *state,
88 uint8_t channels, unsigned src_rate, unsigned dest_rate,
89 GError **error_r)
91 static int convalgo = -1;
92 int error;
93 SRC_DATA *data = &state->data;
95 if (convalgo < 0)
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)
102 return true;
104 state->error = 0;
105 state->prev.channels = channels;
106 state->prev.src_rate = src_rate;
107 state->prev.dest_rate = dest_rate;
109 if (state->state)
110 state->state = src_delete(state->state);
112 state->state = src_new(convalgo, channels, &error);
113 if (!state->state) {
114 g_set_error(error_r, libsamplerate_quark(), state->error,
115 "libsamplerate initialization has failed: %s",
116 src_strerror(error));
117 return false;
120 data->src_ratio = (double)dest_rate / (double)src_rate;
121 g_debug("setting samplerate conversion ratio to %.2lf",
122 data->src_ratio);
123 src_set_ratio(state->state, data->src_ratio);
125 return true;
128 const int16_t *
129 pcm_resample_lsr_16(struct pcm_resample_state *state,
130 uint8_t channels,
131 unsigned src_rate,
132 const int16_t *src_buffer, size_t src_size,
133 unsigned dest_rate, size_t *dest_size_r,
134 GError **error_r)
136 bool success;
137 SRC_DATA *data = &state->data;
138 size_t data_in_size;
139 size_t data_out_size;
140 int error;
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,
146 error_r);
147 if (!success)
148 return NULL;
150 /* there was an error previously, and nothing has changed */
151 if (state->error) {
152 g_set_error(error_r, libsamplerate_quark(), state->error,
153 "libsamplerate has failed: %s",
154 src_strerror(state->error));
155 return NULL;
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);
170 if (error) {
171 g_set_error(error_r, libsamplerate_quark(), error,
172 "libsamplerate has failed: %s",
173 src_strerror(error));
174 state->error = error;
175 return NULL;
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);
184 return dest_buffer;
187 #ifdef HAVE_LIBSAMPLERATE_NOINT
189 /* libsamplerate introduced these functions in v0.1.3 */
191 static void
192 src_int_to_float_array(const int *in, float *out, int len)
194 while (len-- > 0)
195 *out++ = *in++ / (float)(1 << (24 - 1));
198 static void
199 src_float_to_int_array (const float *in, int *out, int len)
201 while (len-- > 0)
202 *out++ = *in++ * (float)(1 << (24 - 1));
205 #endif
207 const int32_t *
208 pcm_resample_lsr_32(struct pcm_resample_state *state,
209 uint8_t channels,
210 unsigned src_rate,
211 const int32_t *src_buffer, size_t src_size,
212 unsigned dest_rate, size_t *dest_size_r,
213 GError **error_r)
215 bool success;
216 SRC_DATA *data = &state->data;
217 size_t data_in_size;
218 size_t data_out_size;
219 int error;
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,
225 error_r);
226 if (!success)
227 return NULL;
229 /* there was an error previously, and nothing has changed */
230 if (state->error) {
231 g_set_error(error_r, libsamplerate_quark(), state->error,
232 "libsamplerate has failed: %s",
233 src_strerror(state->error));
234 return NULL;
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);
249 if (error) {
250 g_set_error(error_r, libsamplerate_quark(), error,
251 "libsamplerate has failed: %s",
252 src_strerror(error));
253 state->error = error;
254 return NULL;
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);
263 return dest_buffer;