VolumeFilterPlugin.cxx 3.1 KB
Newer Older
1
/*
2
 * Copyright (C) 2003-2013 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 "config.h"
21
#include "VolumeFilterPlugin.hxx"
Max Kellermann's avatar
Max Kellermann committed
22 23 24
#include "FilterPlugin.hxx"
#include "FilterInternal.hxx"
#include "FilterRegistry.hxx"
Max Kellermann's avatar
Max Kellermann committed
25
#include "pcm/PcmVolume.hxx"
26
#include "pcm/PcmBuffer.hxx"
27
#include "AudioFormat.hxx"
28 29
#include "util/Error.hxx"
#include "util/Domain.hxx"
30 31 32 33

#include <assert.h>
#include <string.h>

34
class VolumeFilter final : public Filter {
35 36 37 38 39
	/**
	 * The current volume, from 0 to #PCM_VOLUME_1.
	 */
	unsigned volume;

40
	AudioFormat format;
41

42
	PcmBuffer buffer;
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

public:
	VolumeFilter()
		:volume(PCM_VOLUME_1) {}

	unsigned GetVolume() const {
		assert(volume <= PCM_VOLUME_1);

		return volume;
	}

	void SetVolume(unsigned _volume) {
		assert(_volume <= PCM_VOLUME_1);

		volume = _volume;
	}

60
	virtual AudioFormat Open(AudioFormat &af, Error &error) override;
61 62
	virtual void Close();
	virtual const void *FilterPCM(const void *src, size_t src_size,
63
				      size_t *dest_size_r, Error &error);
64 65
};

66
static constexpr Domain volume_domain("pcm_volume");
67

68
static Filter *
69
volume_filter_init(gcc_unused const config_param &param,
70
		   gcc_unused Error &error)
71
{
72
	return new VolumeFilter();
73 74
}

75
AudioFormat
76
VolumeFilter::Open(AudioFormat &audio_format, gcc_unused Error &error)
77
{
78
	format = audio_format;
79

80
	return format;
81 82
}

83 84
void
VolumeFilter::Close()
85
{
86
	buffer.Clear();
87 88
}

89 90
const void *
VolumeFilter::FilterPCM(const void *src, size_t src_size,
91
			size_t *dest_size_r, Error &error)
92
{
93 94
	*dest_size_r = src_size;

95
	if (volume >= PCM_VOLUME_1)
96 97 98
		/* optimized special case: 100% volume = no-op */
		return src;

99
	void *dest = buffer.Get(src_size);
100

101
	if (volume <= 0) {
102 103 104 105 106 107 108 109 110
		/* optimized special case: 0% volume = memset(0) */
		/* XXX is this valid for all sample formats? What
		   about floating point? */
		memset(dest, 0, src_size);
		return dest;
	}

	memcpy(dest, src, src_size);

111
	bool success = pcm_volume(dest, src_size,
112
				  format.format,
113
				  volume);
114
	if (!success) {
115
		error.Set(volume_domain, "pcm_volume() has failed");
116 117 118 119 120 121 122
		return NULL;
	}

	return dest;
}

const struct filter_plugin volume_filter_plugin = {
123 124
	"volume",
	volume_filter_init,
125
};
126 127

unsigned
128
volume_filter_get(const Filter *_filter)
129
{
130 131
	const VolumeFilter *filter =
		(const VolumeFilter *)_filter;
132

133
	return filter->GetVolume();
134 135 136
}

void
137
volume_filter_set(Filter *_filter, unsigned volume)
138
{
139
	VolumeFilter *filter = (VolumeFilter *)_filter;
140

141
	filter->SetVolume(volume);
142 143
}