diff options
Diffstat (limited to 'src/filter/RouteFilterPlugin.cxx')
-rw-r--r-- | src/filter/RouteFilterPlugin.cxx | 297 |
1 files changed, 0 insertions, 297 deletions
diff --git a/src/filter/RouteFilterPlugin.cxx b/src/filter/RouteFilterPlugin.cxx deleted file mode 100644 index d9042c21f..000000000 --- a/src/filter/RouteFilterPlugin.cxx +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (C) 2003-2013 The Music Player Daemon Project - * 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. - */ - -/** \file - * - * This filter copies audio data between channels. Useful for - * upmixing mono/stereo audio to surround speaker configurations. - * - * Its configuration consists of a "filter" section with a single - * "routes" entry, formatted as: \\ - * routes "0>1, 1>0, 2>2, 3>3, 3>4" \\ - * where each pair of numbers signifies a set of channels. - * Each source>dest pair leads to the data from channel #source - * being copied to channel #dest in the output. - * - * Example: \\ - * routes "0>0, 1>1, 0>2, 1>3"\\ - * upmixes stereo audio to a 4-speaker system, copying the front-left - * (0) to front left (0) and rear left (2), copying front-right (1) to - * front-right (1) and rear-right (3). - * - * If multiple sources are copied to the same destination channel, only - * one of them takes effect. - */ - -#include "config.h" -#include "ConfigError.hxx" -#include "ConfigData.hxx" -#include "AudioFormat.hxx" -#include "CheckAudioFormat.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.hxx" -#include "pcm/PcmBuffer.hxx" -#include "util/StringUtil.hxx" -#include "util/Error.hxx" - -#include <algorithm> - -#include <assert.h> -#include <string.h> -#include <stdint.h> -#include <stdlib.h> - -class RouteFilter final : public Filter { - /** - * The minimum number of channels we need for output - * to be able to perform all the copies the user has specified - */ - unsigned min_output_channels; - - /** - * The minimum number of input channels we need to - * copy all the data the user has requested. If fewer - * than this many are supplied by the input, undefined - * copy operations are given zeroed sources in stead. - */ - unsigned min_input_channels; - - /** - * The set of copy operations to perform on each sample - * The index is an output channel to use, the value is - * a corresponding input channel from which to take the - * data. A -1 means "no source" - */ - int8_t sources[MAX_CHANNELS]; - - /** - * The actual input format of our signal, once opened - */ - AudioFormat input_format; - - /** - * The decided upon output format, once opened - */ - AudioFormat output_format; - - /** - * The size, in bytes, of each multichannel frame in the - * input buffer - */ - size_t input_frame_size; - - /** - * The size, in bytes, of each multichannel frame in the - * output buffer - */ - size_t output_frame_size; - - /** - * The output buffer used last time around, can be reused if the size doesn't differ. - */ - PcmBuffer output_buffer; - -public: - /** - * Parse the "routes" section, a string on the form - * a>b, c>d, e>f, ... - * where a... are non-unique, non-negative integers - * and input channel a gets copied to output channel b, etc. - * @param param the configuration block to read - * @param filter a route_filter whose min_channels and sources[] to set - * @return true on success, false on error - */ - bool Configure(const config_param ¶m, Error &error); - - virtual AudioFormat Open(AudioFormat &af, Error &error) override; - virtual void Close(); - virtual const void *FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, Error &error); -}; - -bool -RouteFilter::Configure(const config_param ¶m, Error &error) { - - /* TODO: - * With a more clever way of marking "don't copy to output N", - * This could easily be merged into a single loop with some - * dynamic realloc() instead of one count run and one malloc(). - */ - - std::fill_n(sources, MAX_CHANNELS, -1); - - min_input_channels = 0; - min_output_channels = 0; - - // A cowardly default, just passthrough stereo - const char *routes = param.GetBlockValue("routes", "0>0, 1>1"); - while (true) { - routes = strchug_fast(routes); - - char *endptr; - const unsigned source = strtoul(routes, &endptr, 10); - endptr = strchug_fast(endptr); - if (endptr == routes || *endptr != '>') { - error.Set(config_domain, - "Malformed 'routes' specification"); - return false; - } - - if (source >= MAX_CHANNELS) { - error.Format(config_domain, - "Invalid source channel number: %u", - source); - return false; - } - - if (source >= min_input_channels) - min_input_channels = source + 1; - - routes = strchug_fast(endptr + 1); - - unsigned dest = strtoul(routes, &endptr, 10); - endptr = strchug_fast(endptr); - if (endptr == routes) { - error.Set(config_domain, - "Malformed 'routes' specification"); - return false; - } - - if (dest >= MAX_CHANNELS) { - error.Format(config_domain, - "Invalid destination channel number: %u", - dest); - return false; - } - - if (dest >= min_output_channels) - min_output_channels = dest + 1; - - sources[dest] = source; - - routes = endptr; - - if (*routes == 0) - break; - - if (*routes != ',') { - error.Set(config_domain, - "Malformed 'routes' specification"); - return false; - } - - ++routes; - } - - return true; -} - -static Filter * -route_filter_init(const config_param ¶m, Error &error) -{ - RouteFilter *filter = new RouteFilter(); - if (!filter->Configure(param, error)) { - delete filter; - return nullptr; - } - - return filter; -} - -AudioFormat -RouteFilter::Open(AudioFormat &audio_format, gcc_unused Error &error) -{ - // Copy the input format for later reference - input_format = audio_format; - input_frame_size = input_format.GetFrameSize(); - - // Decide on an output format which has enough channels, - // and is otherwise identical - output_format = audio_format; - output_format.channels = min_output_channels; - - // Precalculate this simple value, to speed up allocation later - output_frame_size = output_format.GetFrameSize(); - - return output_format; -} - -void -RouteFilter::Close() -{ - output_buffer.Clear(); -} - -const void * -RouteFilter::FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, gcc_unused Error &error) -{ - size_t number_of_frames = src_size / input_frame_size; - - const size_t bytes_per_frame_per_channel = input_format.GetSampleSize(); - - // A moving pointer that always refers to channel 0 in the input, at the currently handled frame - const uint8_t *base_source = (const uint8_t *)src; - - // Grow our reusable buffer, if needed, and set the moving pointer - *dest_size_r = number_of_frames * output_frame_size; - void *const result = output_buffer.Get(*dest_size_r); - - // A moving pointer that always refers to the currently filled channel of the currently handled frame, in the output - uint8_t *chan_destination = (uint8_t *)result; - - // Perform our copy operations, with N input channels and M output channels - for (unsigned int s=0; s<number_of_frames; ++s) { - - // Need to perform one copy per output channel - for (unsigned int c=0; c<min_output_channels; ++c) { - if (sources[c] == -1 || - (unsigned)sources[c] >= input_format.channels) { - // No source for this destination output, - // give it zeroes as input - memset(chan_destination, - 0x00, - bytes_per_frame_per_channel); - } else { - // Get the data from channel sources[c] - // and copy it to the output - const uint8_t *data = base_source + - (sources[c] * bytes_per_frame_per_channel); - memcpy(chan_destination, - data, - bytes_per_frame_per_channel); - } - // Move on to the next output channel - chan_destination += bytes_per_frame_per_channel; - } - - - // Go on to the next N input samples - base_source += input_frame_size; - } - - // Here it is, ladies and gentlemen! Rerouted data! - return result; -} - -const struct filter_plugin route_filter_plugin = { - "route", - route_filter_init, -}; |