Convert.cxx 3.31 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright 2003-2019 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 "Convert.hxx"
21
#include "ConfiguredResampler.hxx"
22
#include "util/ConstBuffer.hxx"
23 24

#include <assert.h>
Warren Dukes's avatar
Warren Dukes committed
25

26
void
27
pcm_convert_global_init(const ConfigData &config)
28
{
29
	pcm_resampler_global_init(config);
30 31
}

32
PcmConvert::PcmConvert(const AudioFormat _src_format,
33 34
		       const AudioFormat dest_format)
	:src_format(_src_format)
35
{
36 37
	assert(src_format.IsValid());
	assert(dest_format.IsValid());
38

39
	AudioFormat format = _src_format;
40 41 42
	if (format.format == SampleFormat::DSD)
		format.format = SampleFormat::FLOAT;

43
	enable_resampler = format.sample_rate != dest_format.sample_rate;
44
	if (enable_resampler) {
45
		resampler.Open(format, dest_format.sample_rate);
46 47

		format.format = resampler.GetOutputSampleFormat();
48
		format.sample_rate = dest_format.sample_rate;
49 50
	}

51
	enable_format = format.format != dest_format.format;
52 53 54
	if (enable_format) {
		try {
			format_converter.Open(format.format,
55
					      dest_format.format);
56 57 58 59 60
		} catch (...) {
			if (enable_resampler)
				resampler.Close();
			throw;
		}
61 62
	}

63
	format.format = dest_format.format;
64

65
	enable_channels = format.channels != dest_format.channels;
66 67 68
	if (enable_channels) {
		try {
			channels_converter.Open(format.format, format.channels,
69
						dest_format.channels);
70 71 72 73 74 75 76
		} catch (...) {
			if (enable_format)
				format_converter.Close();
			if (enable_resampler)
				resampler.Close();
			throw;
		}
77
	}
78 79
}

80
PcmConvert::~PcmConvert() noexcept
81
{
82
	if (enable_channels)
83
		channels_converter.Close();
84
	if (enable_format)
85
		format_converter.Close();
86 87
	if (enable_resampler)
		resampler.Close();
88

89
#ifdef ENABLE_DSD
Max Kellermann's avatar
Max Kellermann committed
90
	dsd.Reset();
91
#endif
92 93
}

94
void
Max Kellermann's avatar
Max Kellermann committed
95
PcmConvert::Reset() noexcept
96 97 98 99 100 101 102 103 104
{
	if (enable_resampler)
		resampler.Reset();

#ifdef ENABLE_DSD
	dsd.Reset();
#endif
}

105
ConstBuffer<void>
106
PcmConvert::Convert(ConstBuffer<void> buffer)
107
{
108
#ifdef ENABLE_DSD
109
	if (src_format.format == SampleFormat::DSD) {
110
		auto s = ConstBuffer<uint8_t>::FromVoid(buffer);
111
		auto d = dsd.ToFloat(src_format.channels, s);
112 113
		if (d.IsNull())
			throw std::runtime_error("DSD to PCM conversion failed");
114

115
		buffer = d.ToVoid();
116
	}
117
#endif
118

119 120
	if (enable_resampler)
		buffer = resampler.Resample(buffer);
121

122 123
	if (enable_format)
		buffer = format_converter.Convert(buffer);
124

125 126
	if (enable_channels)
		buffer = channels_converter.Convert(buffer);
127

128
	return buffer;
129
}
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148

ConstBuffer<void>
PcmConvert::Flush()
{
	if (enable_resampler) {
		auto buffer = resampler.Flush();
		if (!buffer.IsNull()) {
			if (enable_format)
				buffer = format_converter.Convert(buffer);

			if (enable_channels)
				buffer = channels_converter.Convert(buffer);

			return buffer;
		}
	}

	return nullptr;
}