PcmChannels.cxx 4.77 KB
Newer Older
1
/*
2
 * Copyright 2003-2016 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"
Max Kellermann's avatar
Max Kellermann committed
21
#include "PcmChannels.hxx"
22
#include "PcmBuffer.hxx"
23 24
#include "Traits.hxx"
#include "AudioFormat.hxx"
25
#include "util/ConstBuffer.hxx"
Max Kellermann's avatar
Max Kellermann committed
26

27 28
#include <assert.h>

29
template<typename D, typename S>
30
static void
31
MonoToStereo(D dest, S src, S end)
32
{
33 34
	while (src != end) {
		const auto value = *src++;
35 36 37 38

		*dest++ = value;
		*dest++ = value;
	}
39

40 41
}

42 43 44 45
template<SampleFormat F, class Traits=SampleTraits<F>>
static typename Traits::value_type
StereoToMono(typename Traits::value_type _a,
	     typename Traits::value_type _b)
46
{
47 48
	typename Traits::sum_type a(_a);
	typename Traits::sum_type b(_b);
49

50
	return typename Traits::value_type((a + b) / 2);
51 52
}

53 54 55 56 57
template<SampleFormat F, class Traits=SampleTraits<F>>
static typename Traits::pointer_type
StereoToMono(typename Traits::pointer_type dest,
	     typename Traits::const_pointer_type src,
	     typename Traits::const_pointer_type end)
58
{
59 60 61
	while (src != end) {
		const auto a = *src++;
		const auto b = *src++;
62

63 64 65 66 67
		*dest++ = StereoToMono<F, Traits>(a, b);
	}

	return dest;
}
68

69 70 71 72 73 74 75 76
template<SampleFormat F, class Traits=SampleTraits<F>>
static typename Traits::pointer_type
NToStereo(typename Traits::pointer_type dest,
	  unsigned src_channels,
	  typename Traits::const_pointer_type src,
	  typename Traits::const_pointer_type end)
{
	assert((end - src) % src_channels == 0);
77

78
	while (src != end) {
79
		typename Traits::sum_type sum = *src++;
80
		for (unsigned c = 1; c < src_channels; ++c)
81 82
			sum += *src++;

83 84 85
		typename Traits::value_type value(sum / int(src_channels));

		/* TODO: this is actually only mono ... */
86 87 88
		*dest++ = value;
		*dest++ = value;
	}
89 90

	return dest;
91 92
}

93 94 95 96 97 98 99 100 101 102 103
template<SampleFormat F, class Traits=SampleTraits<F>>
static typename Traits::pointer_type
NToM(typename Traits::pointer_type dest,
     unsigned dest_channels,
     unsigned src_channels,
     typename Traits::const_pointer_type src,
     typename Traits::const_pointer_type end)
{
	assert((end - src) % src_channels == 0);

	while (src != end) {
104
		typename Traits::sum_type sum = *src++;
105 106 107 108 109 110 111 112 113 114 115 116 117
		for (unsigned c = 1; c < src_channels; ++c)
			sum += *src++;

		typename Traits::value_type value(sum / int(src_channels));

		/* TODO: this is actually only mono ... */
		for (unsigned c = 0; c < dest_channels; ++c)
			*dest++ = value;
	}

	return dest;
}

118 119 120 121 122 123
template<SampleFormat F, class Traits=SampleTraits<F>>
static ConstBuffer<typename Traits::value_type>
ConvertChannels(PcmBuffer &buffer,
		unsigned dest_channels,
		unsigned src_channels,
		ConstBuffer<typename Traits::value_type> src)
124
{
125
	assert(src.size % src_channels == 0);
126

127
	const size_t dest_size = src.size / src_channels * dest_channels;
128
	auto dest = buffer.GetT<typename Traits::value_type>(dest_size);
129

130
	if (src_channels == 1 && dest_channels == 2)
131
		MonoToStereo(dest, src.begin(), src.end());
132
	else if (src_channels == 2 && dest_channels == 1)
133
		StereoToMono<F>(dest, src.begin(), src.end());
134
	else if (dest_channels == 2)
135
		NToStereo<F>(dest, src_channels, src.begin(), src.end());
136
	else
137 138
		NToM<F>(dest, dest_channels,
			src_channels, src.begin(), src.end());
139

140
	return { dest, dest_size };
141
}
142

143 144 145 146 147
ConstBuffer<int16_t>
pcm_convert_channels_16(PcmBuffer &buffer,
			unsigned dest_channels,
			unsigned src_channels,
			ConstBuffer<int16_t> src)
148
{
149 150
	return ConvertChannels<SampleFormat::S16>(buffer, dest_channels,
						  src_channels, src);
151 152
}

153
ConstBuffer<int32_t>
154
pcm_convert_channels_24(PcmBuffer &buffer,
155
			unsigned dest_channels,
156 157
			unsigned src_channels,
			ConstBuffer<int32_t> src)
158
{
159 160
	return ConvertChannels<SampleFormat::S24_P32>(buffer, dest_channels,
						      src_channels, src);
161 162
}

163
ConstBuffer<int32_t>
164
pcm_convert_channels_32(PcmBuffer &buffer,
165
			unsigned dest_channels,
166 167
			unsigned src_channels,
			ConstBuffer<int32_t> src)
168
{
169 170
	return ConvertChannels<SampleFormat::S32>(buffer, dest_channels,
						  src_channels, src);
171 172
}

173
ConstBuffer<float>
174
pcm_convert_channels_float(PcmBuffer &buffer,
175
			   unsigned dest_channels,
176 177
			   unsigned src_channels,
			   ConstBuffer<float> src)
178
{
179 180
	return ConvertChannels<SampleFormat::FLOAT>(buffer, dest_channels,
						    src_channels, src);
181
}