Export.cxx 7.17 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright 2003-2021 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * 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.
 *
 * 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.
 */

20
#include "Export.hxx"
21
#include "Order.hxx"
22
#include "Pack.hxx"
23
#include "Silence.hxx"
24
#include "util/ByteReverse.hxx"
25
#include "util/ConstBuffer.hxx"
26
#include "util/WritableBuffer.hxx"
27

28 29
#include <cassert>

30
#include <string.h>
31

32
void
33
PcmExport::Open(SampleFormat sample_format, unsigned _channels,
34
		Params params) noexcept
35 36 37
{
	assert(audio_valid_sample_format(sample_format));

38
	src_sample_format = sample_format;
39
	channels = _channels;
40
	alsa_channel_order = params.alsa_channel_order;
41 42

#ifdef ENABLE_DSD
43 44
	assert(params.dsd_mode != DsdMode::DOP ||
	       audio_valid_channel_count(_channels));
45

46 47 48 49 50 51 52 53 54
	dsd_mode = sample_format == SampleFormat::DSD
		? params.dsd_mode
		: DsdMode::NONE;

	switch (dsd_mode) {
	case DsdMode::NONE:
		break;

	case DsdMode::U16:
55 56
		dsd16_converter.Open(_channels);

57 58 59
		/* after the conversion to DSD_U16, the DSD samples
		   are stuffed inside fake 16 bit samples */
		sample_format = SampleFormat::S16;
60
		break;
61

62
	case DsdMode::U32:
63 64
		dsd32_converter.Open(_channels);

65 66 67
		/* after the conversion to DSD_U32, the DSD samples
		   are stuffed inside fake 32 bit samples */
		sample_format = SampleFormat::S32;
68
		break;
69

70
	case DsdMode::DOP:
71 72
		dop_converter.Open(_channels);

73
		/* after the conversion to DoP, the DSD
74
		   samples are stuffed inside fake 24 bit samples */
75
		sample_format = SampleFormat::S24_P32;
76
		break;
77
	}
78
#endif
79

80 81
	shift8 = params.shift8 && sample_format == SampleFormat::S24_P32;
	pack24 = params.pack24 && sample_format == SampleFormat::S24_P32;
82 83 84 85

	assert(!shift8 || !pack24);

	reverse_endian = 0;
86
	if (params.reverse_endian) {
87 88 89 90 91 92 93 94
		size_t sample_size = pack24
			? 3
			: sample_format_size(sample_format);
		assert(sample_size <= 0xff);

		if (sample_size > 1)
			reverse_endian = sample_size;
	}
95 96 97 98 99 100 101 102 103 104

	/* prepare a moment of silence for GetSilence() */
	char buffer[sizeof(silence_buffer)];
	const size_t buffer_size = GetInputBlockSize();
	assert(buffer_size < sizeof(buffer));
	PcmSilence({buffer, buffer_size}, src_sample_format);
	auto s = Export({buffer, buffer_size});
	assert(s.size < sizeof(silence_buffer));
	silence_size = s.size;
	memcpy(silence_buffer, s.data, s.size);
105 106
}

107 108 109 110
void
PcmExport::Reset() noexcept
{
#ifdef ENABLE_DSD
111 112
	switch (dsd_mode) {
	case DsdMode::NONE:
113 114
		break;

115
	case DsdMode::U16:
116 117 118
		dsd16_converter.Reset();
		break;

119
	case DsdMode::U32:
120
		dsd32_converter.Reset();
121 122 123
		break;

	case DsdMode::DOP:
124
		dop_converter.Reset();
125 126
		break;
	}
127 128 129
#endif
}

130
size_t
131
PcmExport::GetOutputFrameSize() const noexcept
132 133 134
{
	if (pack24)
		/* packed 24 bit samples (3 bytes per sample) */
135
		return channels * 3;
136

137
#ifdef ENABLE_DSD
138 139 140 141 142
	switch (dsd_mode) {
	case DsdMode::NONE:
		break;

	case DsdMode::U16:
143 144
		return channels * 2;

145
	case DsdMode::U32:
146 147
		return channels * 4;

148
	case DsdMode::DOP:
149 150 151 152 153
		/* the DSD-over-USB draft says that DSD 1-bit samples
		   are enclosed within 24 bit samples, and MPD's
		   representation of 24 bit is padded to 32 bit (4
		   bytes per sample) */
		return channels * 4;
154
	}
155
#endif
156

157
	return GetInputFrameSize();
158 159
}

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
size_t
PcmExport::GetInputBlockSize() const noexcept
{
#ifdef ENABLE_DSD
	switch (dsd_mode) {
	case DsdMode::NONE:
		break;

	case DsdMode::U16:
		return dsd16_converter.GetInputBlockSize();

	case DsdMode::U32:
		return dsd32_converter.GetInputBlockSize();

	case DsdMode::DOP:
		return dop_converter.GetInputBlockSize();
	}
#endif

	return GetInputFrameSize();
}

size_t
PcmExport::GetOutputBlockSize() const noexcept
{
#ifdef ENABLE_DSD
	switch (dsd_mode) {
	case DsdMode::NONE:
		break;

	case DsdMode::U16:
		return dsd16_converter.GetOutputBlockSize();

	case DsdMode::U32:
		return dsd32_converter.GetOutputBlockSize();

	case DsdMode::DOP:
		return dop_converter.GetOutputBlockSize();
	}
#endif

	return GetOutputFrameSize();
}

204 205 206 207 208 209
ConstBuffer<void>
PcmExport::GetSilence() const noexcept
{
	return {silence_buffer, silence_size};
}

210
unsigned
211
PcmExport::Params::CalcOutputSampleRate(unsigned sample_rate) const noexcept
212
{
213
#ifdef ENABLE_DSD
214 215 216 217 218
	switch (dsd_mode) {
	case DsdMode::NONE:
		break;

	case DsdMode::U16:
219 220 221
		/* DSD_U16 combines two 8-bit "samples" in one 16-bit
		   "sample" */
		sample_rate /= 2;
222
		break;
223

224
	case DsdMode::U32:
225 226 227
		/* DSD_U32 combines four 8-bit "samples" in one 32-bit
		   "sample" */
		sample_rate /= 4;
228
		break;
229

230
	case DsdMode::DOP:
231 232 233
		/* DoP packs two 8-bit "samples" in one 24-bit
		   "sample" */
		sample_rate /= 2;
234 235
		break;
	}
236 237
#endif

238 239 240 241
	return sample_rate;
}

unsigned
242
PcmExport::Params::CalcInputSampleRate(unsigned sample_rate) const noexcept
243
{
244
#ifdef ENABLE_DSD
245 246 247 248 249
	switch (dsd_mode) {
	case DsdMode::NONE:
		break;

	case DsdMode::U16:
250
		sample_rate *= 2;
251
		break;
252

253
	case DsdMode::U32:
254
		sample_rate *= 4;
255
		break;
256

257
	case DsdMode::DOP:
258
		sample_rate *= 2;
259 260
		break;
	}
261 262
#endif

263 264 265
	return sample_rate;
}

266
ConstBuffer<void>
267
PcmExport::Export(ConstBuffer<void> data) noexcept
268
{
269
	if (alsa_channel_order)
270
		data = ToAlsaChannelOrder(order_buffer, data,
271
					  src_sample_format, channels);
272

273
#ifdef ENABLE_DSD
274 275 276 277 278
	switch (dsd_mode) {
	case DsdMode::NONE:
		break;

	case DsdMode::U16:
279
		data = dsd16_converter.Convert(ConstBuffer<uint8_t>::FromVoid(data))
280
			.ToVoid();
281
		break;
282

283
	case DsdMode::U32:
284
		data = dsd32_converter.Convert(ConstBuffer<uint8_t>::FromVoid(data))
285
			.ToVoid();
286
		break;
287

288
	case DsdMode::DOP:
289
		data = dop_converter.Convert(ConstBuffer<uint8_t>::FromVoid(data))
290
			.ToVoid();
291 292
		break;
	}
293
#endif
294 295

	if (pack24) {
296 297
		const auto src = ConstBuffer<int32_t>::FromVoid(data);
		const size_t num_samples = src.size;
298
		const size_t dest_size = num_samples * 3;
Max Kellermann's avatar
Max Kellermann committed
299
		auto *dest = (uint8_t *)pack_buffer.Get(dest_size);
300
		assert(dest != nullptr);
301

302
		pcm_pack_24(dest, src.begin(), src.end());
303

304 305
		data.data = dest;
		data.size = dest_size;
306
	} else if (shift8) {
307
		const auto src = ConstBuffer<int32_t>::FromVoid(data);
308

Max Kellermann's avatar
Max Kellermann committed
309
		auto *dest = (uint32_t *)pack_buffer.Get(data.size);
310
		data.data = dest;
311

312 313
		for (auto i : src)
			*dest++ = i << 8;
314 315 316 317 318
	}

	if (reverse_endian > 0) {
		assert(reverse_endian >= 2);

319
		const auto src = ConstBuffer<uint8_t>::FromVoid(data);
320

Max Kellermann's avatar
Max Kellermann committed
321
		auto *dest = (uint8_t *)reverse_buffer.Get(data.size);
322 323
		assert(dest != nullptr);
		data.data = dest;
324

325
		reverse_bytes(dest, src.begin(), src.end(), reverse_endian);
326 327 328 329 330 331
	}

	return data;
}

size_t
332
PcmExport::CalcInputSize(size_t size) const noexcept
333 334 335 336 337
{
	if (pack24)
		/* 32 bit to 24 bit conversion (4 to 3 bytes) */
		size = (size / 3) * 4;

338
#ifdef ENABLE_DSD
339 340 341 342 343 344 345
	switch (dsd_mode) {
	case DsdMode::NONE:
	case DsdMode::U16:
	case DsdMode::U32:
		break;

	case DsdMode::DOP:
346
		/* DoP doubles the transport size */
347
		size /= 2;
348 349
		break;
	}
350
#endif
351 352 353

	return size;
}