pcm_convert.c 8.89 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2011 The Music Player Daemon Project
3
 * http://www.musicpd.org
4 5 6 7 8 9 10 11 12 13
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
14 15 16 17
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 19
 */

20
#include "config.h"
21
#include "pcm_convert.h"
22
#include "pcm_channels.h"
23
#include "pcm_format.h"
24
#include "pcm_pack.h"
25
#include "audio_format.h"
26 27 28 29

#include <assert.h>
#include <string.h>
#include <math.h>
30
#include <glib.h>
Warren Dukes's avatar
Warren Dukes committed
31

Max Kellermann's avatar
Max Kellermann committed
32 33 34
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "pcm"

35 36 37
void pcm_convert_init(struct pcm_convert_state *state)
{
	memset(state, 0, sizeof(*state));
38

39
	pcm_dsd_init(&state->dsd);
40
	pcm_resample_init(&state->resample);
41
	pcm_dither_24_init(&state->dither);
42 43

	pcm_buffer_init(&state->format_buffer);
44
	pcm_buffer_init(&state->channels_buffer);
45 46
}

47 48
void pcm_convert_deinit(struct pcm_convert_state *state)
{
49
	pcm_dsd_deinit(&state->dsd);
50
	pcm_resample_deinit(&state->resample);
51 52

	pcm_buffer_deinit(&state->format_buffer);
53
	pcm_buffer_deinit(&state->channels_buffer);
54 55
}

56 57 58
void
pcm_convert_reset(struct pcm_convert_state *state)
{
59
	pcm_dsd_reset(&state->dsd);
60 61 62
	pcm_resample_reset(&state->resample);
}

63 64 65
static const int16_t *
pcm_convert_16(struct pcm_convert_state *state,
	       const struct audio_format *src_format,
66
	       const void *src_buffer, size_t src_size,
67 68
	       const struct audio_format *dest_format, size_t *dest_size_r,
	       GError **error_r)
69
{
70
	const int16_t *buf;
71
	size_t len;
72

73
	assert(dest_format->format == SAMPLE_FORMAT_S16);
74

75
	buf = pcm_convert_to_16(&state->format_buffer, &state->dither,
76
				src_format->format, src_buffer, src_size,
77
				&len);
78 79
	if (buf == NULL) {
		g_set_error(error_r, pcm_convert_quark(), 0,
80 81
			    "Conversion from %s to 16 bit is not implemented",
			    sample_format_to_string(src_format->format));
82 83
		return NULL;
	}
84

85
	if (src_format->channels != dest_format->channels) {
86 87
		buf = pcm_convert_channels_16(&state->channels_buffer,
					      dest_format->channels,
88
					      src_format->channels,
89
					      buf, len, &len);
90 91 92 93 94 95 96 97
		if (buf == NULL) {
			g_set_error(error_r, pcm_convert_quark(), 0,
				    "Conversion from %u to %u channels "
				    "is not implemented",
				    src_format->channels,
				    dest_format->channels);
			return NULL;
		}
98 99
	}

100
	if (src_format->sample_rate != dest_format->sample_rate) {
101 102
		buf = pcm_resample_16(&state->resample,
				      dest_format->channels,
103
				      src_format->sample_rate, buf, len,
104 105 106 107 108
				      dest_format->sample_rate, &len,
				      error_r);
		if (buf == NULL)
			return NULL;
	}
109

110 111
	*dest_size_r = len;
	return buf;
112 113
}

114 115 116
static const int32_t *
pcm_convert_24(struct pcm_convert_state *state,
	       const struct audio_format *src_format,
117
	       const void *src_buffer, size_t src_size,
118 119
	       const struct audio_format *dest_format, size_t *dest_size_r,
	       GError **error_r)
120 121 122 123
{
	const int32_t *buf;
	size_t len;

124
	assert(dest_format->format == SAMPLE_FORMAT_S24_P32);
125

126
	buf = pcm_convert_to_24(&state->format_buffer, src_format->format,
127
				src_buffer, src_size, &len);
128 129
	if (buf == NULL) {
		g_set_error(error_r, pcm_convert_quark(), 0,
130 131
			    "Conversion from %s to 24 bit is not implemented",
			    sample_format_to_string(src_format->format));
132 133
		return NULL;
	}
134 135

	if (src_format->channels != dest_format->channels) {
136 137
		buf = pcm_convert_channels_24(&state->channels_buffer,
					      dest_format->channels,
138 139
					      src_format->channels,
					      buf, len, &len);
140 141 142 143 144 145 146 147
		if (buf == NULL) {
			g_set_error(error_r, pcm_convert_quark(), 0,
				    "Conversion from %u to %u channels "
				    "is not implemented",
				    src_format->channels,
				    dest_format->channels);
			return NULL;
		}
148 149
	}

150
	if (src_format->sample_rate != dest_format->sample_rate) {
151 152
		buf = pcm_resample_24(&state->resample,
				      dest_format->channels,
153
				      src_format->sample_rate, buf, len,
154 155 156 157 158
				      dest_format->sample_rate, &len,
				      error_r);
		if (buf == NULL)
			return NULL;
	}
159

160 161
	*dest_size_r = len;
	return buf;
162 163
}

164 165 166 167
static const int32_t *
pcm_convert_32(struct pcm_convert_state *state,
	       const struct audio_format *src_format,
	       const void *src_buffer, size_t src_size,
168 169
	       const struct audio_format *dest_format, size_t *dest_size_r,
	       GError **error_r)
170 171 172 173
{
	const int32_t *buf;
	size_t len;

174
	assert(dest_format->format == SAMPLE_FORMAT_S32);
175

176
	buf = pcm_convert_to_32(&state->format_buffer, src_format->format,
177
				src_buffer, src_size, &len);
178 179
	if (buf == NULL) {
		g_set_error(error_r, pcm_convert_quark(), 0,
180
			    "Conversion from %s to 32 bit is not implemented",
181
			    sample_format_to_string(src_format->format));
182 183
		return NULL;
	}
184 185 186 187 188 189

	if (src_format->channels != dest_format->channels) {
		buf = pcm_convert_channels_32(&state->channels_buffer,
					      dest_format->channels,
					      src_format->channels,
					      buf, len, &len);
190 191 192 193 194 195 196 197
		if (buf == NULL) {
			g_set_error(error_r, pcm_convert_quark(), 0,
				    "Conversion from %u to %u channels "
				    "is not implemented",
				    src_format->channels,
				    dest_format->channels);
			return NULL;
		}
198 199
	}

200
	if (src_format->sample_rate != dest_format->sample_rate) {
201 202 203
		buf = pcm_resample_32(&state->resample,
				      dest_format->channels,
				      src_format->sample_rate, buf, len,
204 205 206 207 208
				      dest_format->sample_rate, &len,
				      error_r);
		if (buf == NULL)
			return buf;
	}
209 210 211 212 213

	*dest_size_r = len;
	return buf;
}

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
static const float *
pcm_convert_float(struct pcm_convert_state *state,
		  const struct audio_format *src_format,
		  const void *src_buffer, size_t src_size,
		  const struct audio_format *dest_format, size_t *dest_size_r,
		  GError **error_r)
{
	const float *buffer = src_buffer;
	size_t size = src_size;

	assert(dest_format->format == SAMPLE_FORMAT_FLOAT);

	/* convert to float now */

	buffer = pcm_convert_to_float(&state->format_buffer,
				      src_format->format,
				      buffer, size, &size);
	if (buffer == NULL) {
		g_set_error(error_r, pcm_convert_quark(), 0,
			    "Conversion from %s to float is not implemented",
			    sample_format_to_string(src_format->format));
		return NULL;
	}

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
	/* convert channels */

	if (src_format->channels != dest_format->channels) {
		buffer = pcm_convert_channels_float(&state->channels_buffer,
						    dest_format->channels,
						    src_format->channels,
						    buffer, size, &size);
		if (buffer == NULL) {
			g_set_error(error_r, pcm_convert_quark(), 0,
				    "Conversion from %u to %u channels "
				    "is not implemented",
				    src_format->channels,
				    dest_format->channels);
			return NULL;
		}
	}

255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
	/* resample with float, because this is the best format for
	   libsamplerate */

	if (src_format->sample_rate != dest_format->sample_rate) {
		buffer = pcm_resample_float(&state->resample,
					    dest_format->channels,
					    src_format->sample_rate,
					    buffer, size,
					    dest_format->sample_rate, &size,
					    error_r);
		if (buffer == NULL)
			return NULL;
	}

	*dest_size_r = size;
	return buffer;
}

273 274 275 276 277
const void *
pcm_convert(struct pcm_convert_state *state,
	    const struct audio_format *src_format,
	    const void *src, size_t src_size,
	    const struct audio_format *dest_format,
278 279
	    size_t *dest_size_r,
	    GError **error_r)
280
{
281
	struct audio_format float_format;
282
	if (src_format->format == SAMPLE_FORMAT_DSD) {
283 284 285
		size_t f_size;
		const float *f = pcm_dsd_to_float(&state->dsd,
						  src_format->channels,
286
						  false, src, src_size,
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
						  &f_size);
		if (f == NULL) {
			g_set_error_literal(error_r, pcm_convert_quark(), 0,
					    "DSD to PCM conversion failed");
			return NULL;
		}

		float_format = *src_format;
		float_format.format = SAMPLE_FORMAT_FLOAT;

		src_format = &float_format;
		src = f;
		src_size = f_size;
	}

302 303
	switch (dest_format->format) {
	case SAMPLE_FORMAT_S16:
304 305
		return pcm_convert_16(state,
				      src_format, src, src_size,
306 307
				      dest_format, dest_size_r,
				      error_r);
308

309
	case SAMPLE_FORMAT_S24_P32:
310 311
		return pcm_convert_24(state,
				      src_format, src, src_size,
312 313
				      dest_format, dest_size_r,
				      error_r);
314

315
	case SAMPLE_FORMAT_S32:
316 317
		return pcm_convert_32(state,
				      src_format, src, src_size,
318 319
				      dest_format, dest_size_r,
				      error_r);
320

321 322 323 324 325 326
	case SAMPLE_FORMAT_FLOAT:
		return pcm_convert_float(state,
					 src_format, src, src_size,
					 dest_format, dest_size_r,
					 error_r);

327
	default:
328
		g_set_error(error_r, pcm_convert_quark(), 0,
329 330
			    "PCM conversion to %s is not implemented",
			    sample_format_to_string(dest_format->format));
331
		return NULL;
332 333
	}
}