2
* Copyright (C) 2003-2011 The Music Player Daemon Project
3
* http://www.musicpd.org
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License along
16
* with this program; if not, write to the Free Software Foundation, Inc.,
17
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
* This filter copies audio data between channels. Useful for
23
* upmixing mono/stereo audio to surround speaker configurations.
25
* Its configuration consists of a "filter" section with a single
26
* "routes" entry, formatted as: \\
27
* routes "0>1, 1>0, 2>2, 3>3, 3>4" \\
28
* where each pair of numbers signifies a set of channels.
29
* Each source>dest pair leads to the data from channel #source
30
* being copied to channel #dest in the output.
33
* routes "0>0, 1>1, 0>2, 1>3"\\
34
* upmixes stereo audio to a 4-speaker system, copying the front-left
35
* (0) to front left (0) and rear left (2), copying front-right (1) to
36
* front-right (1) and rear-right (3).
38
* If multiple sources are copied to the same destination channel, only
39
* one of them takes effect.
44
#include "audio_format.h"
45
#include "audio_check.h"
46
#include "filter_plugin.h"
47
#include "filter_internal.h"
48
#include "filter_registry.h"
49
#include "pcm_buffer.h"
59
* Inherit (and support cast to/from) filter
64
* The minimum number of channels we need for output
65
* to be able to perform all the copies the user has specified
67
unsigned char min_output_channels;
70
* The minimum number of input channels we need to
71
* copy all the data the user has requested. If fewer
72
* than this many are supplied by the input, undefined
73
* copy operations are given zeroed sources in stead.
75
unsigned char min_input_channels;
78
* The set of copy operations to perform on each sample
79
* The index is an output channel to use, the value is
80
* a corresponding input channel from which to take the
81
* data. A -1 means "no source"
86
* The actual input format of our signal, once opened
88
struct audio_format input_format;
91
* The decided upon output format, once opened
93
struct audio_format output_format;
96
* The size, in bytes, of each multichannel frame in the
99
size_t input_frame_size;
102
* The size, in bytes, of each multichannel frame in the
105
size_t output_frame_size;
108
* The output buffer used last time around, can be reused if the size doesn't differ.
110
struct pcm_buffer output_buffer;
115
* Parse the "routes" section, a string on the form
117
* where a... are non-unique, non-negative integers
118
* and input channel a gets copied to output channel b, etc.
119
* @param param the configuration block to read
120
* @param filter a route_filter whose min_channels and sources[] to set
121
* @return true on success, false on error
124
route_filter_parse(const struct config_param *param,
125
struct route_filter *filter,
129
* With a more clever way of marking "don't copy to output N",
130
* This could easily be merged into a single loop with some
131
* dynamic g_realloc() instead of one count run and one g_malloc().
135
int number_of_copies;
137
// A cowardly default, just passthrough stereo
139
config_get_block_string(param, "routes", "0>0, 1>1");
141
filter->min_input_channels = 0;
142
filter->min_output_channels = 0;
144
tokens = g_strsplit(routes, ",", 255);
145
number_of_copies = g_strv_length(tokens);
147
// Start by figuring out a few basic things about the routing set
148
for (int c=0; c<number_of_copies; ++c) {
150
// String and int representations of the source/destination
154
// Squeeze whitespace
155
g_strstrip(tokens[c]);
157
// Split the a>b string into source and destination
158
sd = g_strsplit(tokens[c], ">", 2);
159
if (g_strv_length(sd) != 2) {
160
g_set_error(error_r, config_quark(), 1,
161
"Invalid copy around %d in routes spec: %s",
162
param->line, tokens[c]);
168
source = strtol(sd[0], NULL, 10);
169
dest = strtol(sd[1], NULL, 10);
171
// Keep track of the highest channel numbers seen
172
// as either in- or outputs
173
if (source >= filter->min_input_channels)
174
filter->min_input_channels = source + 1;
175
if (dest >= filter->min_output_channels)
176
filter->min_output_channels = dest + 1;
181
if (!audio_valid_channel_count(filter->min_output_channels)) {
183
g_set_error(error_r, audio_format_quark(), 0,
184
"Invalid number of output channels requested: %d",
185
filter->min_output_channels);
189
// Allocate a map of "copy nothing to me"
191
g_malloc(filter->min_output_channels * sizeof(signed char));
193
for (int i=0; i<filter->min_output_channels; ++i)
194
filter->sources[i] = -1;
196
// Run through the spec again, and save the
197
// actual mapping output <- input
198
for (int c=0; c<number_of_copies; ++c) {
200
// String and int representations of the source/destination
204
// Split the a>b string into source and destination
205
sd = g_strsplit(tokens[c], ">", 2);
206
if (g_strv_length(sd) != 2) {
207
g_set_error(error_r, config_quark(), 1,
208
"Invalid copy around %d in routes spec: %s",
209
param->line, tokens[c]);
215
source = strtol(sd[0], NULL, 10);
216
dest = strtol(sd[1], NULL, 10);
218
filter->sources[dest] = source;
228
static struct filter *
229
route_filter_init(const struct config_param *param,
230
G_GNUC_UNUSED GError **error_r)
232
struct route_filter *filter = g_new(struct route_filter, 1);
233
filter_init(&filter->base, &route_filter_plugin);
235
// Allocate and set the filter->sources[] array
236
route_filter_parse(param, filter, error_r);
238
return &filter->base;
242
route_filter_finish(struct filter *_filter)
244
struct route_filter *filter = (struct route_filter *)_filter;
246
g_free(filter->sources);
250
static const struct audio_format *
251
route_filter_open(struct filter *_filter, struct audio_format *audio_format,
252
G_GNUC_UNUSED GError **error_r)
254
struct route_filter *filter = (struct route_filter *)_filter;
256
// Copy the input format for later reference
257
filter->input_format = *audio_format;
258
filter->input_frame_size =
259
audio_format_frame_size(&filter->input_format);
261
// Decide on an output format which has enough channels,
262
// and is otherwise identical
263
filter->output_format = *audio_format;
264
filter->output_format.channels = filter->min_output_channels;
266
// Precalculate this simple value, to speed up allocation later
267
filter->output_frame_size =
268
audio_format_frame_size(&filter->output_format);
270
// This buffer grows as needed
271
pcm_buffer_init(&filter->output_buffer);
273
return &filter->output_format;
277
route_filter_close(struct filter *_filter)
279
struct route_filter *filter = (struct route_filter *)_filter;
281
pcm_buffer_deinit(&filter->output_buffer);
285
route_filter_filter(struct filter *_filter,
286
const void *src, size_t src_size,
287
size_t *dest_size_r, G_GNUC_UNUSED GError **error_r)
289
struct route_filter *filter = (struct route_filter *)_filter;
291
size_t number_of_frames = src_size / filter->input_frame_size;
293
size_t bytes_per_frame_per_channel =
294
audio_format_sample_size(&filter->input_format);
296
// A moving pointer that always refers to channel 0 in the input, at the currently handled frame
297
const uint8_t *base_source = src;
299
// A moving pointer that always refers to the currently filled channel of the currently handled frame, in the output
300
uint8_t *chan_destination;
302
// Grow our reusable buffer, if needed, and set the moving pointer
303
*dest_size_r = number_of_frames * filter->output_frame_size;
304
chan_destination = pcm_buffer_get(&filter->output_buffer, *dest_size_r);
307
// Perform our copy operations, with N input channels and M output channels
308
for (unsigned int s=0; s<number_of_frames; ++s) {
310
// Need to perform one copy per output channel
311
for (unsigned int c=0; c<filter->min_output_channels; ++c) {
312
if (filter->sources[c] == -1 ||
313
(unsigned)filter->sources[c] >= filter->input_format.channels) {
314
// No source for this destination output,
315
// give it zeroes as input
316
memset(chan_destination,
318
bytes_per_frame_per_channel);
320
// Get the data from channel sources[c]
321
// and copy it to the output
322
const uint8_t *data = base_source +
323
(filter->sources[c] * bytes_per_frame_per_channel);
324
memcpy(chan_destination,
326
bytes_per_frame_per_channel);
328
// Move on to the next output channel
329
chan_destination += bytes_per_frame_per_channel;
333
// Go on to the next N input samples
334
base_source += filter->input_frame_size;
337
// Here it is, ladies and gentlemen! Rerouted data!
338
return (void *) filter->output_buffer.buffer;
341
const struct filter_plugin route_filter_plugin = {
343
.init = route_filter_init,
344
.finish = route_filter_finish,
345
.open = route_filter_open,
346
.close = route_filter_close,
347
.filter = route_filter_filter,