PcmMix.cxx 5.87 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright 2003-2017 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"
Max Kellermann's avatar
Max Kellermann committed
21
#include "PcmMix.hxx"
22
#include "Volume.hxx"
Max Kellermann's avatar
Max Kellermann committed
23
#include "PcmUtils.hxx"
24
#include "Traits.hxx"
25
#include "util/Clamp.hxx"
26

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

29
#include <assert.h>
30 31
#include <math.h>

32 33
template<SampleFormat F, class Traits=SampleTraits<F>>
static typename Traits::value_type
34 35
PcmAddVolume(PcmDither &dither,
	     typename Traits::value_type _a, typename Traits::value_type _b,
36
	     int volume1, int volume2)
37
{
38
	typename Traits::long_type a(_a), b(_b);
39
	typename Traits::long_type c(a * volume1 + b * volume2);
40

41 42 43
	return dither.DitherShift<typename Traits::long_type,
				  Traits::BITS + PCM_VOLUME_BITS,
				  Traits::BITS>(c);
44 45
}

46
template<SampleFormat F, class Traits=SampleTraits<F>>
47
static void
48 49
PcmAddVolume(PcmDither &dither,
	     typename Traits::pointer_type a,
50 51
	     typename Traits::const_pointer_type b,
	     size_t n, int volume1, int volume2)
52
{
53
	for (size_t i = 0; i != n; ++i)
54 55
		a[i] = PcmAddVolume<F, Traits>(dither, a[i], b[i],
					       volume1, volume2);
56 57
}

58
template<SampleFormat F, class Traits=SampleTraits<F>>
59
static void
60 61
PcmAddVolumeVoid(PcmDither &dither,
		 void *a, const void *b, size_t size, int volume1, int volume2)
62
{
63
	constexpr size_t sample_size = Traits::SAMPLE_SIZE;
64
	assert(size % sample_size == 0);
65

66 67
	PcmAddVolume<F, Traits>(dither,
				typename Traits::pointer_type(a),
68 69 70
				typename Traits::const_pointer_type(b),
				size / sample_size,
				volume1, volume2);
71 72
}

73 74 75 76 77 78 79 80 81 82 83 84 85 86
static void
pcm_add_vol_float(float *buffer1, const float *buffer2,
		  unsigned num_samples, float volume1, float volume2)
{
	while (num_samples > 0) {
		float sample1 = *buffer1;
		float sample2 = *buffer2++;

		sample1 = (sample1 * volume1 + sample2 * volume2);
		*buffer1++ = sample1;
		--num_samples;
	}
}

87
static bool
88
pcm_add_vol(PcmDither &dither, void *buffer1, const void *buffer2, size_t size,
89
	    int vol1, int vol2,
90
	    SampleFormat format)
91
{
92
	switch (format) {
93 94
	case SampleFormat::UNDEFINED:
	case SampleFormat::DSD:
95 96 97
		/* not implemented */
		return false;

98
	case SampleFormat::S8:
99 100
		PcmAddVolumeVoid<SampleFormat::S8>(dither,
						   buffer1, buffer2, size,
101
						   vol1, vol2);
102
		return true;
103

104
	case SampleFormat::S16:
105 106
		PcmAddVolumeVoid<SampleFormat::S16>(dither,
						    buffer1, buffer2, size,
107
						    vol1, vol2);
108
		return true;
109

110
	case SampleFormat::S24_P32:
111 112
		PcmAddVolumeVoid<SampleFormat::S24_P32>(dither,
							buffer1, buffer2, size,
113
							vol1, vol2);
114
		return true;
115

116
	case SampleFormat::S32:
117 118
		PcmAddVolumeVoid<SampleFormat::S32>(dither,
						    buffer1, buffer2, size,
119
						    vol1, vol2);
120
		return true;
121

122
	case SampleFormat::FLOAT:
Max Kellermann's avatar
Max Kellermann committed
123 124
		pcm_add_vol_float((float *)buffer1, (const float *)buffer2,
				  size / 4,
125 126 127
				  pcm_volume_to_float(vol1),
				  pcm_volume_to_float(vol2));
		return true;
128
	}
129 130

	assert(false);
131
	gcc_unreachable();
132 133
}

134 135 136
template<SampleFormat F, class Traits=SampleTraits<F>>
static typename Traits::value_type
PcmAdd(typename Traits::value_type _a, typename Traits::value_type _b)
137
{
138
	typename Traits::sum_type a(_a), b(_b);
139

140
	return PcmClamp<F, Traits>(a + b);
141 142
}

143
template<SampleFormat F, class Traits=SampleTraits<F>>
144
static void
145 146 147
PcmAdd(typename Traits::pointer_type a,
       typename Traits::const_pointer_type b,
       size_t n)
148
{
149
	for (size_t i = 0; i != n; ++i)
150
		a[i] = PcmAdd<F, Traits>(a[i], b[i]);
151 152
}

153
template<SampleFormat F, class Traits=SampleTraits<F>>
154
static void
155
PcmAddVoid(void *a, const void *b, size_t size)
156
{
157
	constexpr size_t sample_size = Traits::SAMPLE_SIZE;
158
	assert(size % sample_size == 0);
159

160 161 162
	PcmAdd<F, Traits>(typename Traits::pointer_type(a),
			  typename Traits::const_pointer_type(b),
			  size / sample_size);
163 164
}

165 166 167 168 169 170 171 172 173 174 175
static void
pcm_add_float(float *buffer1, const float *buffer2, unsigned num_samples)
{
	while (num_samples > 0) {
		float sample1 = *buffer1;
		float sample2 = *buffer2++;
		*buffer1++ = sample1 + sample2;
		--num_samples;
	}
}

176
static bool
177
pcm_add(void *buffer1, const void *buffer2, size_t size,
178
	SampleFormat format)
179
{
180
	switch (format) {
181 182
	case SampleFormat::UNDEFINED:
	case SampleFormat::DSD:
183 184 185
		/* not implemented */
		return false;

186
	case SampleFormat::S8:
187
		PcmAddVoid<SampleFormat::S8>(buffer1, buffer2, size);
188
		return true;
189

190
	case SampleFormat::S16:
191
		PcmAddVoid<SampleFormat::S16>(buffer1, buffer2, size);
192
		return true;
193

194
	case SampleFormat::S24_P32:
195
		PcmAddVoid<SampleFormat::S24_P32>(buffer1, buffer2, size);
196
		return true;
197

198
	case SampleFormat::S32:
199
		PcmAddVoid<SampleFormat::S32>(buffer1, buffer2, size);
200
		return true;
201

202
	case SampleFormat::FLOAT:
Max Kellermann's avatar
Max Kellermann committed
203 204
		pcm_add_float((float *)buffer1, (const float *)buffer2,
			      size / 4);
205
		return true;
206
	}
207 208

	assert(false);
209
	gcc_unreachable();
210 211
}

212
bool
213
pcm_mix(PcmDither &dither, void *buffer1, const void *buffer2, size_t size,
214
	SampleFormat format, float portion1)
215
{
216 217
	float s;

218
	/* portion1 is between 0.0 and 1.0 for crossfading, MixRamp uses -1
219
	 * to signal mixing rather than fading */
220
	if (portion1 < 0)
221
		return pcm_add(buffer1, buffer2, size, format);
222 223

	s = sin(M_PI_2 * portion1);
224 225
	s *= s;

226 227
	int vol1 = s * PCM_VOLUME_1S + 0.5;
	vol1 = Clamp<int>(vol1, 0, PCM_VOLUME_1S);
228

229 230
	return pcm_add_vol(dither, buffer1, buffer2, size,
			   vol1, PCM_VOLUME_1S - vol1, format);
231
}