1 /*****************************************************************************
2 * filters.c : audio output filters management
3 *****************************************************************************
4 * Copyright (C) 2002-2007 VLC authors and VideoLAN
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_dialog.h>
36 #include <vlc_modules.h>
38 #include <vlc_filter.h>
39 #include <vlc_vout.h> /* for vout_Request */
40 #include <vlc_input.h>
43 #include "aout_internal.h"
45 static filter_t *CreateFilter (vlc_object_t *obj, const char *type,
46 const char *name, filter_owner_sys_t *owner,
47 const audio_sample_format_t *infmt,
48 const audio_sample_format_t *outfmt)
50 filter_t *filter = vlc_custom_create (obj, sizeof (*filter), type);
51 if (unlikely(filter == NULL))
54 filter->p_owner = owner;
55 filter->fmt_in.audio = *infmt;
56 filter->fmt_in.i_codec = infmt->i_format;
57 filter->fmt_out.audio = *outfmt;
58 filter->fmt_out.i_codec = outfmt->i_format;
59 filter->p_module = module_need (filter, type, name, false);
60 if (filter->p_module == NULL)
62 /* If probing failed, formats shall not have been modified. */
63 assert (AOUT_FMTS_IDENTICAL(&filter->fmt_in.audio, infmt));
64 assert (AOUT_FMTS_IDENTICAL(&filter->fmt_out.audio, outfmt));
65 vlc_object_release (filter);
69 assert (filter->pf_audio_filter != NULL);
73 static filter_t *FindConverter (vlc_object_t *obj,
74 const audio_sample_format_t *infmt,
75 const audio_sample_format_t *outfmt)
77 return CreateFilter (obj, "audio converter", NULL, NULL, infmt, outfmt);
80 static filter_t *FindResampler (vlc_object_t *obj,
81 const audio_sample_format_t *infmt,
82 const audio_sample_format_t *outfmt)
84 return CreateFilter (obj, "audio resampler", "$audio-resampler", NULL,
89 * Destroys a chain of audio filters.
91 static void aout_FiltersPipelineDestroy(filter_t *const *filters, unsigned n)
93 for( unsigned i = 0; i < n; i++ )
95 filter_t *p_filter = filters[i];
97 module_unneed( p_filter, p_filter->p_module );
98 vlc_object_release( p_filter );
102 static filter_t *TryFormat (vlc_object_t *obj, vlc_fourcc_t codec,
103 audio_sample_format_t *restrict fmt)
105 audio_sample_format_t output = *fmt;
107 assert (codec != fmt->i_format);
108 output.i_format = codec;
109 aout_FormatPrepare (&output);
111 filter_t *filter = FindConverter (obj, fmt, &output);
118 * Allocates audio format conversion filters
119 * @param obj parent VLC object for new filters
120 * @param filters table of filters [IN/OUT]
121 * @param count pointer to the number of filters in the table [IN/OUT]
122 * @param max size of filters table [IN]
123 * @param infmt input audio format
124 * @param outfmt output audio format
125 * @return 0 on success, -1 on failure
127 static int aout_FiltersPipelineCreate(vlc_object_t *obj, filter_t **filters,
128 unsigned *count, unsigned max,
129 const audio_sample_format_t *restrict infmt,
130 const audio_sample_format_t *restrict outfmt)
132 aout_FormatsPrint (obj, "conversion:", infmt, outfmt);
136 /* There is a lot of second guessing on what the conversion plugins can
137 * and cannot do. This seems hardly avoidable, the conversion problem need
138 * to be reduced somehow. */
139 audio_sample_format_t input = *infmt;
142 /* Encapsulate or decode non-linear formats */
143 if (!AOUT_FMT_LINEAR(infmt) && infmt->i_format != outfmt->i_format)
148 filter_t *f = TryFormat (obj, VLC_CODEC_S32N, &input);
150 f = TryFormat (obj, VLC_CODEC_FL32, &input);
153 msg_Err (obj, "cannot find %s for conversion pipeline",
160 assert (AOUT_FMT_LINEAR(&input));
163 if (infmt->i_physical_channels != outfmt->i_physical_channels
164 || infmt->i_original_channels != outfmt->i_original_channels)
165 { /* Remixing currently requires FL32... TODO: S16N */
166 if (input.i_format != VLC_CODEC_FL32)
171 filter_t *f = TryFormat (obj, VLC_CODEC_FL32, &input);
174 msg_Err (obj, "cannot find %s for conversion pipeline",
175 "pre-mix converter");
185 audio_sample_format_t output;
186 output.i_format = input.i_format;
187 output.i_rate = input.i_rate;
188 output.i_physical_channels = outfmt->i_physical_channels;
189 output.i_original_channels = outfmt->i_original_channels;
190 aout_FormatPrepare (&output);
192 filter_t *f = FindConverter (obj, &input, &output);
195 msg_Err (obj, "cannot find %s for conversion pipeline",
205 if (input.i_rate != outfmt->i_rate)
206 { /* Resampling works with any linear format, but may be ugly. */
210 audio_sample_format_t output = input;
211 output.i_rate = outfmt->i_rate;
213 filter_t *f = FindConverter (obj, &input, &output);
216 msg_Err (obj, "cannot find %s for conversion pipeline",
226 if (input.i_format != outfmt->i_format)
231 filter_t *f = TryFormat (obj, outfmt->i_format, &input);
234 msg_Err (obj, "cannot find %s for conversion pipeline",
235 "post-mix converter");
241 msg_Dbg (obj, "conversion pipeline complete");
246 msg_Err (obj, "maximum of %u conversion filters reached", max);
247 dialog_Fatal (obj, _("Audio filtering failed"),
248 _("The maximum number of filters (%u) was reached."), max);
250 aout_FiltersPipelineDestroy (filters, n);
255 * Filters an audio buffer through a chain of filters.
257 static block_t *aout_FiltersPipelinePlay(filter_t *const *filters,
258 unsigned count, block_t *block)
260 /* TODO: use filter chain */
261 for (unsigned i = 0; (i < count) && (block != NULL); i++)
263 filter_t *filter = filters[i];
265 /* Please note that p_block->i_nb_samples & i_buffer
266 * shall be set by the filter plug-in. */
267 block = filter->pf_audio_filter (filter, block);
272 #define AOUT_MAX_FILTERS 10
276 filter_t *rate_filter; /**< The filter adjusting samples count
277 (either the scaletempo filter or a resampler) */
278 filter_t *resampler; /**< The resampler */
279 int resampling; /**< Current resampling (Hz) */
281 unsigned count; /**< Number of filters */
282 filter_t *tab[AOUT_MAX_FILTERS]; /**< Configured user filters
283 (e.g. equalization) and their conversions */
286 /** Callback for visualization selection */
287 static int VisualizationCallback (vlc_object_t *obj, const char *var,
288 vlc_value_t oldval, vlc_value_t newval,
291 const char *mode = newval.psz_string;
295 /* FIXME: This ugly hack enforced by visual effect-list, as is the need for
296 * separate "visual" (external) and "audio-visual" (internal) variables...
297 * The visual plugin should have one submodule per effect instead. */
298 if (strcasecmp (mode, "none") && strcasecmp (mode, "goom")
299 && strcasecmp (mode, "projectm") && strcasecmp (mode, "vsxu")
300 && strcasecmp (mode, "glspectrum"))
302 var_Create (obj, "effect-list", VLC_VAR_STRING);
303 var_SetString (obj, "effect-list", mode);
307 var_SetString (obj, "audio-visual", mode);
308 aout_InputRequestRestart ((audio_output_t *)obj);
309 (void) var; (void) oldval; (void) data;
313 static int EqualizerCallback (vlc_object_t *obj, const char *var,
314 vlc_value_t oldval, vlc_value_t newval,
317 const char *val = newval.psz_string;
318 if (!strcmp("equalizer", var) && *val)
320 var_Create (obj, "equalizer-preset", VLC_VAR_STRING);
321 var_SetString (obj, "equalizer-preset", val);
324 if (aout_ChangeFilterString (obj, obj, "audio-filter", "equalizer", *val))
325 aout_InputRequestRestart ((audio_output_t *)obj); /* <- That sucks! */
327 (void) var; (void) oldval; (void) data;
331 vout_thread_t *aout_filter_RequestVout (filter_t *filter, vout_thread_t *vout,
334 /* NOTE: This only works from aout_filters_t.
335 * If you want to use visualization filters from another place, you will
336 * need to add a new pf_aout_request_vout callback or store a pointer
337 * to aout_request_vout_t inside filter_t (i.e. a level of indirection). */
338 const aout_request_vout_t *req = (void *)filter->p_owner;
339 char *visual = var_InheritString (filter->p_parent, "audio-visual");
340 bool recycle = (visual != NULL) && strcasecmp(visual, "none");
343 return req->pf_request_vout (req->p_private, vout, fmt, recycle);
346 static int AppendFilter(vlc_object_t *obj, const char *type, const char *name,
347 aout_filters_t *restrict filters, const void *owner,
348 audio_sample_format_t *restrict infmt,
349 const audio_sample_format_t *restrict outfmt)
351 const unsigned max = sizeof (filters->tab) / sizeof (filters->tab[0]);
352 if (filters->count >= max)
354 msg_Err (obj, "maximum of %u filters reached", max);
358 filter_t *filter = CreateFilter (obj, type, name,
359 (void *)owner, infmt, outfmt);
362 msg_Err (obj, "cannot add user %s \"%s\" (skipped)", type, name);
366 /* convert to the filter input format if necessary */
367 if (aout_FiltersPipelineCreate (obj, filters->tab, &filters->count,
368 max - 1, infmt, &filter->fmt_in.audio))
370 msg_Err (filter, "cannot add user %s \"%s\" (skipped)", type, name);
371 module_unneed (filter, filter->p_module);
372 vlc_object_release (filter);
376 assert (filters->count < max);
377 filters->tab[filters->count] = filter;
379 *infmt = filter->fmt_out.audio;
383 #undef aout_FiltersNew
385 * Sets a chain of audio filters up.
386 * \param obj parent object for the filters
387 * \param infmt chain input format [IN]
388 * \param outfmt chain output format [IN]
389 * \param request_vout visualization video output request callback
390 * \return a filters chain or NULL on failure
393 * *request_vout (if not NULL) must remain valid until aout_FiltersDelete().
396 * If request_vout is non NULL, obj is assumed to be an audio_output_t pointer.
398 aout_filters_t *aout_FiltersNew (vlc_object_t *obj,
399 const audio_sample_format_t *restrict infmt,
400 const audio_sample_format_t *restrict outfmt,
401 const aout_request_vout_t *request_vout)
403 aout_filters_t *filters = malloc (sizeof (*filters));
404 if (unlikely(filters == NULL))
407 filters->rate_filter = NULL;
408 filters->resampler = NULL;
409 filters->resampling = 0;
412 /* Prepare format structure */
413 aout_FormatPrint (obj, "input", infmt);
414 audio_sample_format_t input_format = *infmt;
415 audio_sample_format_t output_format = *outfmt;
417 /* Callbacks (before reading values and also before return statement) */
418 if (request_vout != NULL)
420 var_AddCallback (obj, "equalizer", EqualizerCallback, NULL);
421 var_AddCallback (obj, "equalizer-bands", EqualizerCallback, NULL);
422 var_AddCallback (obj, "visual", VisualizationCallback, NULL);
424 var_TriggerCallback( obj, "equalizer-bands" );
427 /* Now add user filters */
428 if (!AOUT_FMT_LINEAR(outfmt))
429 { /* Non-linear output: just convert formats, no filters/visu */
430 if (!AOUT_FMTS_IDENTICAL(infmt, outfmt))
432 aout_FormatsPrint (obj, "pass-through:", infmt, outfmt);
433 filters->tab[0] = FindConverter(obj, infmt, outfmt);
434 if (filters->tab[0] == NULL)
436 msg_Err (obj, "cannot setup pass-through");
444 /* parse user filter lists */
445 if (var_InheritBool (obj, "audio-time-stretch"))
447 if (AppendFilter(obj, "audio filter", "scaletempo",
448 filters, NULL, &input_format, &output_format) == 0)
449 filters->rate_filter = filters->tab[filters->count - 1];
452 char *str = var_InheritString (obj, "audio-filter");
455 char *p = str, *name;
456 while ((name = strsep (&p, " :")) != NULL)
458 AppendFilter(obj, "audio filter", name, filters,
459 NULL, &input_format, &output_format);
464 if (request_vout != NULL)
466 char *visual = var_InheritString (obj, "audio-visual");
467 if (visual != NULL && strcasecmp (visual, "none"))
468 AppendFilter(obj, "visualization", visual, filters,
469 request_vout, &input_format, &output_format);
473 /* convert to the output format (minus resampling) if necessary */
474 output_format.i_rate = input_format.i_rate;
475 if (aout_FiltersPipelineCreate (obj, filters->tab, &filters->count,
476 AOUT_MAX_FILTERS, &input_format, &output_format))
478 msg_Err (obj, "cannot setup filtering pipeline");
481 input_format = output_format;
483 /* insert the resampler */
484 output_format.i_rate = outfmt->i_rate;
485 assert (AOUT_FMTS_IDENTICAL(&output_format, outfmt));
486 filters->resampler = FindResampler (obj, &input_format,
488 if (filters->resampler == NULL && input_format.i_rate != outfmt->i_rate)
490 msg_Err (obj, "cannot setup a resampler");
493 if (filters->rate_filter == NULL)
494 filters->rate_filter = filters->resampler;
499 aout_FiltersPipelineDestroy (filters->tab, filters->count);
500 var_DelCallback (obj, "equalizer", EqualizerCallback, NULL);
501 var_DelCallback (obj, "equalizer-bands", EqualizerCallback, NULL);
502 var_DelCallback (obj, "visual", VisualizationCallback, NULL);
507 #undef aout_FiltersDelete
509 * Destroys a chain of audio filters.
510 * \param obj object used with aout_FiltersNew()
511 * \param filters chain to be destroyed
513 * obj must be NULL iff request_vout was NULL in aout_FiltersNew()
514 * (this implies obj is an audio_output_t pointer if non NULL).
516 void aout_FiltersDelete (vlc_object_t *obj, aout_filters_t *filters)
518 if (filters->resampler != NULL)
519 aout_FiltersPipelineDestroy (&filters->resampler, 1);
520 aout_FiltersPipelineDestroy (filters->tab, filters->count);
523 var_DelCallback (obj, "equalizer", EqualizerCallback, NULL);
524 var_DelCallback (obj, "equalizer-bands", EqualizerCallback, NULL);
525 var_DelCallback (obj, "visual", VisualizationCallback, NULL);
530 bool aout_FiltersAdjustResampling (aout_filters_t *filters, int adjust)
532 if (filters->resampler == NULL)
536 filters->resampling += adjust;
538 filters->resampling = 0;
539 return filters->resampling != 0;
542 block_t *aout_FiltersPlay (aout_filters_t *filters, block_t *block, int rate)
544 int nominal_rate = 0;
546 if (rate != INPUT_RATE_DEFAULT)
548 filter_t *rate_filter = filters->rate_filter;
550 if (rate_filter == NULL)
551 goto drop; /* Without linear, non-nominal rate is impossible. */
553 /* Override input rate */
554 nominal_rate = rate_filter->fmt_in.audio.i_rate;
555 rate_filter->fmt_in.audio.i_rate =
556 (nominal_rate * INPUT_RATE_DEFAULT) / rate;
559 block = aout_FiltersPipelinePlay (filters->tab, filters->count, block);
560 if (filters->resampler != NULL)
561 { /* NOTE: the resampler needs to run even if resampling is 0.
562 * The decoder and output rates can still be different. */
563 filters->resampler->fmt_in.audio.i_rate += filters->resampling;
564 block = aout_FiltersPipelinePlay (&filters->resampler, 1, block);
565 filters->resampler->fmt_in.audio.i_rate -= filters->resampling;
568 if (nominal_rate != 0)
569 { /* Restore input rate */
570 assert (filters->rate_filter != NULL);
571 filters->rate_filter->fmt_in.audio.i_rate = nominal_rate;
576 block_Release (block);