PcmConvert.cxx 8.46 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 "PcmConvert.hxx"
Max Kellermann's avatar
Max Kellermann committed
22 23
#include "PcmChannels.hxx"
#include "PcmFormat.hxx"
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
PcmConvert::PcmConvert()
36
{
37
	memset(this, 0, sizeof(*this));
38

39 40
	pcm_dsd_init(&dsd);
	pcm_resample_init(&resample);
41

42 43
	pcm_buffer_init(&format_buffer);
	pcm_buffer_init(&channels_buffer);
44 45
}

46
PcmConvert::~PcmConvert()
47
{
48 49
	pcm_dsd_deinit(&dsd);
	pcm_resample_deinit(&resample);
50

51 52
	pcm_buffer_deinit(&format_buffer);
	pcm_buffer_deinit(&channels_buffer);
53 54
}

55
void
56
PcmConvert::Reset()
57
{
58 59
	pcm_dsd_reset(&dsd);
	pcm_resample_reset(&resample);
60 61
}

62 63 64 65 66
inline const int16_t *
PcmConvert::Convert16(const audio_format *src_format,
		      const void *src_buffer, size_t src_size,
		      const audio_format *dest_format, size_t *dest_size_r,
		      GError **error_r)
67
{
68
	const int16_t *buf;
69
	size_t len;
70

71
	assert(dest_format->format == SAMPLE_FORMAT_S16);
72

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

84
	if (src_format->channels != dest_format->channels) {
85
		buf = pcm_convert_channels_16(&channels_buffer,
86
					      dest_format->channels,
87
					      src_format->channels,
88
					      buf, len, &len);
89 90 91 92 93 94 95 96
		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;
		}
97 98
	}

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

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

113 114 115 116 117
inline const int32_t *
PcmConvert::Convert24(const audio_format *src_format,
		      const void *src_buffer, size_t src_size,
		      const audio_format *dest_format, size_t *dest_size_r,
		      GError **error_r)
118 119 120 121
{
	const int32_t *buf;
	size_t len;

122
	assert(dest_format->format == SAMPLE_FORMAT_S24_P32);
123

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

	if (src_format->channels != dest_format->channels) {
135
		buf = pcm_convert_channels_24(&channels_buffer,
136
					      dest_format->channels,
137 138
					      src_format->channels,
					      buf, len, &len);
139 140 141 142 143 144 145 146
		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;
		}
147 148
	}

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

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

163 164 165 166 167
inline const int32_t *
PcmConvert::Convert32(const audio_format *src_format,
		      const void *src_buffer, size_t src_size,
		      const audio_format *dest_format, size_t *dest_size_r,
		      GError **error_r)
168 169 170 171
{
	const int32_t *buf;
	size_t len;

172
	assert(dest_format->format == SAMPLE_FORMAT_S32);
173

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

	if (src_format->channels != dest_format->channels) {
185
		buf = pcm_convert_channels_32(&channels_buffer,
186 187 188
					      dest_format->channels,
					      src_format->channels,
					      buf, len, &len);
189 190 191 192 193 194 195 196
		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;
		}
197 198
	}

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

	*dest_size_r = len;
	return buf;
}

213 214 215 216 217
inline const float *
PcmConvert::ConvertFloat(const audio_format *src_format,
			 const void *src_buffer, size_t src_size,
			 const audio_format *dest_format, size_t *dest_size_r,
			 GError **error_r)
218
{
219
	const float *buffer = (const float *)src_buffer;
220 221 222 223 224 225
	size_t size = src_size;

	assert(dest_format->format == SAMPLE_FORMAT_FLOAT);

	/* convert to float now */

226 227
	buffer = pcm_convert_to_float(&format_buffer,
				      sample_format(src_format->format),
228 229 230 231
				      buffer, size, &size);
	if (buffer == NULL) {
		g_set_error(error_r, pcm_convert_quark(), 0,
			    "Conversion from %s to float is not implemented",
232
			    sample_format_to_string(sample_format(src_format->format)));
233 234 235
		return NULL;
	}

236 237 238
	/* convert channels */

	if (src_format->channels != dest_format->channels) {
239
		buffer = pcm_convert_channels_float(&channels_buffer,
240 241 242 243 244 245 246 247 248 249 250 251 252
						    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;
		}
	}

253 254 255 256
	/* resample with float, because this is the best format for
	   libsamplerate */

	if (src_format->sample_rate != dest_format->sample_rate) {
257
		buffer = pcm_resample_float(&resample,
258 259 260 261 262 263 264 265 266 267 268 269 270
					    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;
}

271
const void *
272 273 274 275 276
PcmConvert::Convert(const audio_format *src_format,
		    const void *src, size_t src_size,
		    const audio_format *dest_format,
		    size_t *dest_size_r,
		    GError **error_r)
277
{
278
	struct audio_format float_format;
279
	if (src_format->format == SAMPLE_FORMAT_DSD) {
280
		size_t f_size;
281
		const float *f = pcm_dsd_to_float(&dsd,
282
						  src_format->channels,
283 284
						  false, (const uint8_t *)src,
						  src_size, &f_size);
285 286 287 288 289 290 291 292 293 294 295 296 297 298
		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;
	}

299
	switch (sample_format(dest_format->format)) {
300
	case SAMPLE_FORMAT_S16:
301 302 303
		return Convert16(src_format, src, src_size,
				 dest_format, dest_size_r,
				 error_r);
304

305
	case SAMPLE_FORMAT_S24_P32:
306 307 308
		return Convert24(src_format, src, src_size,
				 dest_format, dest_size_r,
				 error_r);
309

310
	case SAMPLE_FORMAT_S32:
311 312 313
		return Convert32(src_format, src, src_size,
				 dest_format, dest_size_r,
				 error_r);
314

315
	case SAMPLE_FORMAT_FLOAT:
316 317 318
		return ConvertFloat(src_format, src, src_size,
				    dest_format, dest_size_r,
				    error_r);
319

320
	default:
321
		g_set_error(error_r, pcm_convert_quark(), 0,
322
			    "PCM conversion to %s is not implemented",
323
			    sample_format_to_string(sample_format(dest_format->format)));
324
		return NULL;
325 326
	}
}