pcm_format.c 6.63 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2011 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13
 * http://www.musicpd.org
 *
 * 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_format.h"
22
#include "pcm_dither.h"
23
#include "pcm_buffer.h"
24
#include "pcm_pack.h"
25 26 27 28 29 30 31 32 33 34 35 36

static void
pcm_convert_8_to_16(int16_t *out, const int8_t *in,
		    unsigned num_samples)
{
	while (num_samples > 0) {
		*out++ = *in++ << 8;
		--num_samples;
	}
}

static void
37
pcm_convert_24_to_16(struct pcm_dither *dither,
38 39 40 41 42 43
		     int16_t *out, const int32_t *in,
		     unsigned num_samples)
{
	pcm_dither_24_to_16(dither, out, in, num_samples);
}

44 45 46 47 48 49 50 51
static void
pcm_convert_32_to_16(struct pcm_dither *dither,
		     int16_t *out, const int32_t *in,
		     unsigned num_samples)
{
	pcm_dither_32_to_16(dither, out, in, num_samples);
}

52 53 54 55 56 57 58 59 60
static int32_t *
pcm_convert_24_to_24p32(struct pcm_buffer *buffer, const uint8_t *src,
			unsigned num_samples)
{
	int32_t *dest = pcm_buffer_get(buffer, num_samples * 4);
	pcm_unpack_24(dest, src, num_samples, false);
	return dest;
}

61
const int16_t *
62
pcm_convert_to_16(struct pcm_buffer *buffer, struct pcm_dither *dither,
63
		  enum sample_format src_format, const void *src,
64 65 66
		  size_t src_size, size_t *dest_size_r)
{
	unsigned num_samples;
67
	int16_t *dest;
68
	int32_t *dest32;
69

70 71 72 73 74
	switch (src_format) {
	case SAMPLE_FORMAT_UNDEFINED:
		break;

	case SAMPLE_FORMAT_S8:
75
		num_samples = src_size;
76 77
		*dest_size_r = src_size * sizeof(*dest);
		dest = pcm_buffer_get(buffer, *dest_size_r);
78

79
		pcm_convert_8_to_16(dest,
80 81
				    (const int8_t *)src,
				    num_samples);
82
		return dest;
83

84
	case SAMPLE_FORMAT_S16:
85 86 87
		*dest_size_r = src_size;
		return src;

88 89 90 91 92 93 94 95 96 97 98 99 100
	case SAMPLE_FORMAT_S24:
		/* convert to S24_P32 first */
		num_samples = src_size / 3;

		dest32 = pcm_convert_24_to_24p32(buffer, src, num_samples);
		dest = (int16_t *)dest32;

		/* convert to 16 bit in-place */
		*dest_size_r = num_samples * sizeof(*dest);
		pcm_convert_24_to_16(dither, dest, dest32,
				     num_samples);
		return dest;

101
	case SAMPLE_FORMAT_S24_P32:
102
		num_samples = src_size / 4;
103 104 105 106
		*dest_size_r = num_samples * sizeof(*dest);
		dest = pcm_buffer_get(buffer, *dest_size_r);

		pcm_convert_24_to_16(dither, dest,
107 108
				     (const int32_t *)src,
				     num_samples);
109
		return dest;
110

111
	case SAMPLE_FORMAT_S32:
112 113 114 115 116 117 118 119
		num_samples = src_size / 4;
		*dest_size_r = num_samples * sizeof(*dest);
		dest = pcm_buffer_get(buffer, *dest_size_r);

		pcm_convert_32_to_16(dither, dest,
				     (const int32_t *)src,
				     num_samples);
		return dest;
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
	}

	return NULL;
}

static void
pcm_convert_8_to_24(int32_t *out, const int8_t *in,
		    unsigned num_samples)
{
	while (num_samples > 0) {
		*out++ = *in++ << 16;
		--num_samples;
	}
}

static void
pcm_convert_16_to_24(int32_t *out, const int16_t *in,
		     unsigned num_samples)
{
	while (num_samples > 0) {
		*out++ = *in++ << 8;
		--num_samples;
	}
}

145
static void
146
pcm_convert_32_to_24(int32_t *out, const int32_t *in,
147 148 149 150 151 152 153 154
		     unsigned num_samples)
{
	while (num_samples > 0) {
		*out++ = *in++ >> 8;
		--num_samples;
	}
}

155
const int32_t *
156
pcm_convert_to_24(struct pcm_buffer *buffer,
157
		  enum sample_format src_format, const void *src,
158 159 160
		  size_t src_size, size_t *dest_size_r)
{
	unsigned num_samples;
161
	int32_t *dest;
162

163 164 165 166 167
	switch (src_format) {
	case SAMPLE_FORMAT_UNDEFINED:
		break;

	case SAMPLE_FORMAT_S8:
168
		num_samples = src_size;
169 170
		*dest_size_r = src_size * sizeof(*dest);
		dest = pcm_buffer_get(buffer, *dest_size_r);
171

172
		pcm_convert_8_to_24(dest, (const int8_t *)src,
173
				    num_samples);
174
		return dest;
175

176
	case SAMPLE_FORMAT_S16:
177
		num_samples = src_size / 2;
178 179
		*dest_size_r = num_samples * sizeof(*dest);
		dest = pcm_buffer_get(buffer, *dest_size_r);
180

181
		pcm_convert_16_to_24(dest, (const int16_t *)src,
182
				     num_samples);
183
		return dest;
184

185 186 187 188 189 190
	case SAMPLE_FORMAT_S24:
		num_samples = src_size / 3;
		*dest_size_r = num_samples * sizeof(*dest);

		return pcm_convert_24_to_24p32(buffer, src, num_samples);

191
	case SAMPLE_FORMAT_S24_P32:
192 193
		*dest_size_r = src_size;
		return src;
194

195
	case SAMPLE_FORMAT_S32:
196 197 198 199
		num_samples = src_size / 4;
		*dest_size_r = num_samples * sizeof(*dest);
		dest = pcm_buffer_get(buffer, *dest_size_r);

200
		pcm_convert_32_to_24(dest, (const int32_t *)src,
201 202
				     num_samples);
		return dest;
203 204 205 206
	}

	return NULL;
}
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239

static void
pcm_convert_8_to_32(int32_t *out, const int8_t *in,
		    unsigned num_samples)
{
	while (num_samples > 0) {
		*out++ = *in++ << 24;
		--num_samples;
	}
}

static void
pcm_convert_16_to_32(int32_t *out, const int16_t *in,
		     unsigned num_samples)
{
	while (num_samples > 0) {
		*out++ = *in++ << 16;
		--num_samples;
	}
}

static void
pcm_convert_24_to_32(int32_t *out, const int32_t *in,
		     unsigned num_samples)
{
	while (num_samples > 0) {
		*out++ = *in++ << 8;
		--num_samples;
	}
}

const int32_t *
pcm_convert_to_32(struct pcm_buffer *buffer,
240
		  enum sample_format src_format, const void *src,
241 242 243 244 245
		  size_t src_size, size_t *dest_size_r)
{
	unsigned num_samples;
	int32_t *dest;

246 247 248 249 250
	switch (src_format) {
	case SAMPLE_FORMAT_UNDEFINED:
		break;

	case SAMPLE_FORMAT_S8:
251 252 253 254 255 256 257 258
		num_samples = src_size;
		*dest_size_r = src_size * sizeof(*dest);
		dest = pcm_buffer_get(buffer, *dest_size_r);

		pcm_convert_8_to_32(dest, (const int8_t *)src,
				    num_samples);
		return dest;

259
	case SAMPLE_FORMAT_S16:
260 261 262 263 264 265 266 267
		num_samples = src_size / 2;
		*dest_size_r = num_samples * sizeof(*dest);
		dest = pcm_buffer_get(buffer, *dest_size_r);

		pcm_convert_16_to_32(dest, (const int16_t *)src,
				     num_samples);
		return dest;

268 269 270 271 272 273 274 275 276 277 278
	case SAMPLE_FORMAT_S24:
		/* convert to S24_P32 first */
		num_samples = src_size / 3;

		dest = pcm_convert_24_to_24p32(buffer, src, num_samples);

		/* convert to 32 bit in-place */
		*dest_size_r = num_samples * sizeof(*dest);
		pcm_convert_24_to_32(dest, dest, num_samples);
		return dest;

279
	case SAMPLE_FORMAT_S24_P32:
280 281 282 283 284 285 286 287
		num_samples = src_size / 4;
		*dest_size_r = num_samples * sizeof(*dest);
		dest = pcm_buffer_get(buffer, *dest_size_r);

		pcm_convert_24_to_32(dest, (const int32_t *)src,
				     num_samples);
		return dest;

288
	case SAMPLE_FORMAT_S32:
289 290 291 292 293 294
		*dest_size_r = src_size;
		return src;
	}

	return NULL;
}