PcmFormat.cxx 10.6 KB
Newer Older
1
/*
2
 * Copyright 2003-2018 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
 */

Max Kellermann's avatar
Max Kellermann committed
20
#include "PcmFormat.hxx"
21
#include "PcmBuffer.hxx"
22
#include "Clamp.hxx"
23
#include "Traits.hxx"
24 25
#include "FloatConvert.hxx"
#include "ShiftConvert.hxx"
26
#include "util/ConstBuffer.hxx"
27

28 29
#include "PcmDither.cxx" // including the .cxx file to get inlined templates

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
/**
 * Wrapper for a class that converts one sample at a time into one
 * that converts a buffer at a time.
 */
template<typename C>
struct PerSampleConvert : C {
	typedef typename C::SrcTraits SrcTraits;
	typedef typename C::DstTraits DstTraits;

	void Convert(typename DstTraits::pointer_type gcc_restrict out,
		     typename SrcTraits::const_pointer_type gcc_restrict in,
		     size_t n) const {
		for (size_t i = 0; i != n; ++i)
			out[i] = C::Convert(in[i]);
	}
};
46

47 48 49
struct Convert8To16
	: PerSampleConvert<LeftShiftSampleConvert<SampleFormat::S8,
						  SampleFormat::S16>> {};
50

51 52 53
struct Convert24To16 {
	typedef SampleTraits<SampleFormat::S24_P32> SrcTraits;
	typedef SampleTraits<SampleFormat::S16> DstTraits;
54

55 56 57 58 59 60 61 62 63 64 65 66
	PcmDither &dither;

	Convert24To16(PcmDither &_dither):dither(_dither) {}

	void Convert(int16_t *out, const int32_t *in, size_t n) {
		dither.Dither24To16(out, in, in + n);
	}
};

struct Convert32To16 {
	typedef SampleTraits<SampleFormat::S32> SrcTraits;
	typedef SampleTraits<SampleFormat::S16> DstTraits;
67

68 69 70 71 72 73
	PcmDither &dither;

	Convert32To16(PcmDither &_dither):dither(_dither) {}

	void Convert(int16_t *out, const int32_t *in, size_t n) {
		dither.Dither32To16(out, in, in + n);
74
	}
75 76 77
};

template<SampleFormat F, class Traits=SampleTraits<F>>
78
struct PortableFloatToInteger
79 80
	: PerSampleConvert<FloatToIntegerSampleConvert<F, Traits>> {};

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
template<SampleFormat F, class Traits=SampleTraits<F>>
struct FloatToInteger : PortableFloatToInteger<F, Traits> {};

/**
 * A template class that attempts to use the "optimized" algorithm for
 * large portions of the buffer, and calls the "portable" algorithm"
 * for the rest when the last block is not full.
 */
template<typename Optimized, typename Portable>
class GlueOptimizedConvert : Optimized, Portable {
public:
	typedef typename Portable::SrcTraits SrcTraits;
	typedef typename Portable::DstTraits DstTraits;

	void Convert(typename DstTraits::pointer_type out,
		     typename SrcTraits::const_pointer_type in,
		     size_t n) const {
		Optimized::Convert(out, in, n);

		/* use the "portable" algorithm for the trailing
		   samples */
		size_t remaining = n % Optimized::BLOCK_SIZE;
		size_t done = n - remaining;
		Portable::Convert(out + done, in + done, remaining);
	}
};

#ifdef __ARM_NEON__
#include "Neon.hxx"

template<>
struct FloatToInteger<SampleFormat::S16, SampleTraits<SampleFormat::S16>>
	: GlueOptimizedConvert<NeonFloatTo16,
			       PortableFloatToInteger<SampleFormat::S16>> {};

#endif

118
template<class C>
119
static ConstBuffer<typename C::DstTraits::value_type>
120 121 122 123 124 125
AllocateConvert(PcmBuffer &buffer, C convert,
		ConstBuffer<typename C::SrcTraits::value_type> src)
{
	auto dest = buffer.GetT<typename C::DstTraits::value_type>(src.size);
	convert.Convert(dest, src.data, src.size);
	return { dest, src.size };
126 127
}

128
template<SampleFormat F, class Traits=SampleTraits<F>>
129
static ConstBuffer<typename Traits::value_type>
130
AllocateFromFloat(PcmBuffer &buffer, ConstBuffer<float> src)
131
{
132
	return AllocateConvert(buffer, FloatToInteger<F, Traits>(), src);
133 134
}

135 136 137
static ConstBuffer<int16_t>
pcm_allocate_8_to_16(PcmBuffer &buffer, ConstBuffer<int8_t> src)
{
138
	return AllocateConvert(buffer, Convert8To16(), src);
139 140 141
}

static ConstBuffer<int16_t>
142
pcm_allocate_24p32_to_16(PcmBuffer &buffer, PcmDither &dither,
143 144
			 ConstBuffer<int32_t> src)
{
145
	return AllocateConvert(buffer, Convert24To16(dither), src);
146 147
}

148
static ConstBuffer<int16_t>
149
pcm_allocate_32_to_16(PcmBuffer &buffer, PcmDither &dither,
150 151
		      ConstBuffer<int32_t> src)
{
152
	return AllocateConvert(buffer, Convert32To16(dither), src);
153 154
}

155 156
static ConstBuffer<int16_t>
pcm_allocate_float_to_16(PcmBuffer &buffer, ConstBuffer<float> src)
157
{
158
	return AllocateFromFloat<SampleFormat::S16>(buffer, src);
159 160
}

161
ConstBuffer<int16_t>
162
pcm_convert_to_16(PcmBuffer &buffer, PcmDither &dither,
163
		  SampleFormat src_format, ConstBuffer<void> src) noexcept
164
{
165
	switch (src_format) {
166 167
	case SampleFormat::UNDEFINED:
	case SampleFormat::DSD:
168 169
		break;

170
	case SampleFormat::S8:
171
		return pcm_allocate_8_to_16(buffer,
172
					    ConstBuffer<int8_t>::FromVoid(src));
173

174
	case SampleFormat::S16:
175
		return ConstBuffer<int16_t>::FromVoid(src);
176

177
	case SampleFormat::S24_P32:
Max Kellermann's avatar
Max Kellermann committed
178
		return pcm_allocate_24p32_to_16(buffer, dither,
179
						ConstBuffer<int32_t>::FromVoid(src));
180

181
	case SampleFormat::S32:
Max Kellermann's avatar
Max Kellermann committed
182
		return pcm_allocate_32_to_16(buffer, dither,
183
					     ConstBuffer<int32_t>::FromVoid(src));
184

185
	case SampleFormat::FLOAT:
Max Kellermann's avatar
Max Kellermann committed
186
		return pcm_allocate_float_to_16(buffer,
187
						ConstBuffer<float>::FromVoid(src));
188 189
	}

190
	return nullptr;
191 192
}

193 194 195
struct Convert8To24
	: PerSampleConvert<LeftShiftSampleConvert<SampleFormat::S8,
						  SampleFormat::S24_P32>> {};
196

197 198 199
struct Convert16To24
	: PerSampleConvert<LeftShiftSampleConvert<SampleFormat::S16,
						  SampleFormat::S24_P32>> {};
200

201 202
static ConstBuffer<int32_t>
pcm_allocate_8_to_24(PcmBuffer &buffer, ConstBuffer<int8_t> src)
203
{
204
	return AllocateConvert(buffer, Convert8To24(), src);
205 206
}

207 208
static ConstBuffer<int32_t>
pcm_allocate_16_to_24(PcmBuffer &buffer, ConstBuffer<int16_t> src)
209
{
210
	return AllocateConvert(buffer, Convert16To24(), src);
211 212
}

213 214 215 216
struct Convert32To24
	: PerSampleConvert<RightShiftSampleConvert<SampleFormat::S32,
						   SampleFormat::S24_P32>> {};

217 218
static ConstBuffer<int32_t>
pcm_allocate_32_to_24(PcmBuffer &buffer, ConstBuffer<int32_t> src)
219
{
220
	return AllocateConvert(buffer, Convert32To24(), src);
221 222
}

223
static ConstBuffer<int32_t>
224
pcm_allocate_float_to_24(PcmBuffer &buffer, ConstBuffer<float> src)
225
{
226
	return AllocateFromFloat<SampleFormat::S24_P32>(buffer, src);
227 228
}

229
ConstBuffer<int32_t>
230
pcm_convert_to_24(PcmBuffer &buffer,
231
		  SampleFormat src_format, ConstBuffer<void> src) noexcept
232
{
233
	switch (src_format) {
234 235
	case SampleFormat::UNDEFINED:
	case SampleFormat::DSD:
236 237
		break;

238
	case SampleFormat::S8:
239
		return pcm_allocate_8_to_24(buffer,
240
					    ConstBuffer<int8_t>::FromVoid(src));
241

242
	case SampleFormat::S16:
243
		return pcm_allocate_16_to_24(buffer,
244
					     ConstBuffer<int16_t>::FromVoid(src));
245

246
	case SampleFormat::S24_P32:
247
		return ConstBuffer<int32_t>::FromVoid(src);
248

249
	case SampleFormat::S32:
Max Kellermann's avatar
Max Kellermann committed
250
		return pcm_allocate_32_to_24(buffer,
251
					     ConstBuffer<int32_t>::FromVoid(src));
252

253
	case SampleFormat::FLOAT:
254 255
		return pcm_allocate_float_to_24(buffer,
						ConstBuffer<float>::FromVoid(src));
256 257
	}

258
	return nullptr;
259
}
260

261 262 263
struct Convert8To32
	: PerSampleConvert<LeftShiftSampleConvert<SampleFormat::S8,
						  SampleFormat::S32>> {};
264

265 266 267
struct Convert16To32
	: PerSampleConvert<LeftShiftSampleConvert<SampleFormat::S16,
						  SampleFormat::S32>> {};
268

269 270 271
struct Convert24To32
	: PerSampleConvert<LeftShiftSampleConvert<SampleFormat::S24_P32,
						  SampleFormat::S32>> {};
272

273 274
static ConstBuffer<int32_t>
pcm_allocate_8_to_32(PcmBuffer &buffer, ConstBuffer<int8_t> src)
275
{
276
	return AllocateConvert(buffer, Convert8To32(), src);
277 278
}

279 280
static ConstBuffer<int32_t>
pcm_allocate_16_to_32(PcmBuffer &buffer, ConstBuffer<int16_t> src)
281
{
282
	return AllocateConvert(buffer, Convert16To32(), src);
283 284
}

285 286
static ConstBuffer<int32_t>
pcm_allocate_24p32_to_32(PcmBuffer &buffer, ConstBuffer<int32_t> src)
287
{
288
	return AllocateConvert(buffer, Convert24To32(), src);
289 290
}

291 292
static ConstBuffer<int32_t>
pcm_allocate_float_to_32(PcmBuffer &buffer, ConstBuffer<float> src)
293
{
294
	return AllocateFromFloat<SampleFormat::S32>(buffer, src);
295 296
}

297
ConstBuffer<int32_t>
298
pcm_convert_to_32(PcmBuffer &buffer,
299
		  SampleFormat src_format, ConstBuffer<void> src) noexcept
300
{
301
	switch (src_format) {
302 303
	case SampleFormat::UNDEFINED:
	case SampleFormat::DSD:
304 305
		break;

306
	case SampleFormat::S8:
Max Kellermann's avatar
Max Kellermann committed
307
		return pcm_allocate_8_to_32(buffer,
308
					    ConstBuffer<int8_t>::FromVoid(src));
309

310
	case SampleFormat::S16:
Max Kellermann's avatar
Max Kellermann committed
311
		return pcm_allocate_16_to_32(buffer,
312
					     ConstBuffer<int16_t>::FromVoid(src));
313

314
	case SampleFormat::S24_P32:
Max Kellermann's avatar
Max Kellermann committed
315
		return pcm_allocate_24p32_to_32(buffer,
316
						ConstBuffer<int32_t>::FromVoid(src));
317

318
	case SampleFormat::S32:
319
		return ConstBuffer<int32_t>::FromVoid(src);
320

321
	case SampleFormat::FLOAT:
Max Kellermann's avatar
Max Kellermann committed
322
		return pcm_allocate_float_to_32(buffer,
323
						ConstBuffer<float>::FromVoid(src));
324 325
	}

326
	return nullptr;
327
}
328

329 330
struct Convert8ToFloat
	: PerSampleConvert<IntegerToFloatSampleConvert<SampleFormat::S8>> {};
331

332 333 334 335 336 337 338 339
struct Convert16ToFloat
	: PerSampleConvert<IntegerToFloatSampleConvert<SampleFormat::S16>> {};

struct Convert24ToFloat
	: PerSampleConvert<IntegerToFloatSampleConvert<SampleFormat::S24_P32>> {};

struct Convert32ToFloat
	: PerSampleConvert<IntegerToFloatSampleConvert<SampleFormat::S32>> {};
340

341 342
static ConstBuffer<float>
pcm_allocate_8_to_float(PcmBuffer &buffer, ConstBuffer<int8_t> src)
343
{
344
	return AllocateConvert(buffer, Convert8ToFloat(), src);
345 346
}

347 348
static ConstBuffer<float>
pcm_allocate_16_to_float(PcmBuffer &buffer, ConstBuffer<int16_t> src)
349
{
350
	return AllocateConvert(buffer, Convert16ToFloat(), src);
351 352
}

353 354
static ConstBuffer<float>
pcm_allocate_24p32_to_float(PcmBuffer &buffer, ConstBuffer<int32_t> src)
355
{
356
	return AllocateConvert(buffer, Convert24ToFloat(), src);
357 358
}

359 360
static ConstBuffer<float>
pcm_allocate_32_to_float(PcmBuffer &buffer, ConstBuffer<int32_t> src)
361
{
362
	return AllocateConvert(buffer, Convert32ToFloat(), src);
363 364
}

365
ConstBuffer<float>
366
pcm_convert_to_float(PcmBuffer &buffer,
367
		     SampleFormat src_format, ConstBuffer<void> src) noexcept
368 369
{
	switch (src_format) {
370 371
	case SampleFormat::UNDEFINED:
	case SampleFormat::DSD:
372 373
		break;

374
	case SampleFormat::S8:
375
		return pcm_allocate_8_to_float(buffer,
376
					       ConstBuffer<int8_t>::FromVoid(src));
377

378
	case SampleFormat::S16:
379
		return pcm_allocate_16_to_float(buffer,
380
					       ConstBuffer<int16_t>::FromVoid(src));
381

382
	case SampleFormat::S32:
383
		return pcm_allocate_32_to_float(buffer,
384 385 386 387 388
					       ConstBuffer<int32_t>::FromVoid(src));

	case SampleFormat::S24_P32:
		return pcm_allocate_24p32_to_float(buffer,
						   ConstBuffer<int32_t>::FromVoid(src));
389

390
	case SampleFormat::FLOAT:
391
		return ConstBuffer<float>::FromVoid(src);
392 393
	}

394
	return nullptr;
395
}