1 /*****************************************************************************
2 * filters.c : audio output filters management
3 *****************************************************************************
4 * Copyright (C) 2002-2007 VLC authors and VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_dialog.h>
36 #include <vlc_modules.h>
38 #include <vlc_filter.h>
40 #include "aout_internal.h"
41 #include "../video_output/vout_internal.h" /* for vout_Request */
43 filter_t
*aout_filter_Create(vlc_object_t
*obj
, const filter_owner_t
*restrict owner
,
44 const char *type
, const char *name
,
45 const audio_sample_format_t
*infmt
,
46 const audio_sample_format_t
*outfmt
,
47 config_chain_t
*cfg
, bool const_fmt
)
49 filter_t
*filter
= vlc_custom_create (obj
, sizeof (*filter
), type
);
50 if (unlikely(filter
== NULL
))
54 filter
->owner
= *owner
;
56 filter
->fmt_in
.audio
= *infmt
;
57 filter
->fmt_in
.i_codec
= infmt
->i_format
;
58 filter
->fmt_out
.audio
= *outfmt
;
59 filter
->fmt_out
.i_codec
= outfmt
->i_format
;
62 /* Assure that infmt/oufmt are well prepared and that channels
63 * configurations are valid*/
64 if( infmt
->i_physical_channels
!= 0 )
65 assert( aout_FormatNbChannels( infmt
) == infmt
->i_channels
);
66 if( outfmt
->i_physical_channels
!= 0 )
67 assert( aout_FormatNbChannels( outfmt
) == outfmt
->i_channels
);
70 filter
->p_module
= module_need (filter
, type
, name
, false);
73 if (filter
->p_module
== NULL
|| const_fmt
)
75 /* If probing failed, formats shall not have been modified. */
76 assert (AOUT_FMTS_IDENTICAL(&filter
->fmt_in
.audio
, infmt
));
77 assert (AOUT_FMTS_IDENTICAL(&filter
->fmt_out
.audio
, outfmt
));
81 if (filter
->p_module
== NULL
)
83 vlc_object_delete(filter
);
87 assert (filter
->pf_audio_filter
!= NULL
);
91 static filter_t
*FindConverter (vlc_object_t
*obj
,
92 const audio_sample_format_t
*infmt
,
93 const audio_sample_format_t
*outfmt
)
95 return aout_filter_Create(obj
, NULL
, "audio converter", NULL
, infmt
, outfmt
,
99 static filter_t
*FindResampler (vlc_object_t
*obj
,
100 const audio_sample_format_t
*infmt
,
101 const audio_sample_format_t
*outfmt
)
103 char *modlist
= var_InheritString(obj
, "audio-resampler");
104 filter_t
*filter
= aout_filter_Create(obj
, NULL
, "audio resampler", modlist
,
105 infmt
, outfmt
, NULL
, true);
111 * Destroys a chain of audio filters.
113 static void aout_FiltersPipelineDestroy(filter_t
*const *filters
, unsigned n
)
115 for( unsigned i
= 0; i
< n
; i
++ )
117 filter_t
*p_filter
= filters
[i
];
119 module_unneed( p_filter
, p_filter
->p_module
);
120 vlc_object_delete(p_filter
);
124 static filter_t
*TryFormat (vlc_object_t
*obj
, vlc_fourcc_t codec
,
125 audio_sample_format_t
*restrict fmt
)
127 audio_sample_format_t output
= *fmt
;
129 assert (codec
!= fmt
->i_format
);
130 output
.i_format
= codec
;
131 aout_FormatPrepare (&output
);
133 filter_t
*filter
= FindConverter (obj
, fmt
, &output
);
140 * Allocates audio format conversion filters
141 * @param obj parent VLC object for new filters
142 * @param filters table of filters [IN/OUT]
143 * @param count pointer to the number of filters in the table [IN/OUT]
144 * @param max size of filters table [IN]
145 * @param infmt input audio format
146 * @param outfmt output audio format
147 * @return 0 on success, -1 on failure
149 static int aout_FiltersPipelineCreate(vlc_object_t
*obj
, filter_t
**filters
,
150 unsigned *count
, unsigned max
,
151 const audio_sample_format_t
*restrict infmt
,
152 const audio_sample_format_t
*restrict outfmt
,
155 aout_FormatsPrint (obj
, "conversion:", infmt
, outfmt
);
159 /* There is a lot of second guessing on what the conversion plugins can
160 * and cannot do. This seems hardly avoidable, the conversion problem need
161 * to be reduced somehow. */
162 audio_sample_format_t input
= *infmt
;
165 if (!AOUT_FMT_LINEAR(&input
))
167 msg_Err(obj
, "Can't convert non linear input");
172 if (infmt
->i_physical_channels
!= outfmt
->i_physical_channels
173 || infmt
->i_chan_mode
!= outfmt
->i_chan_mode
174 || infmt
->channel_type
!= outfmt
->channel_type
)
175 { /* Remixing currently requires FL32... TODO: S16N */
176 if (input
.i_format
!= VLC_CODEC_FL32
)
181 filter_t
*f
= TryFormat (obj
, VLC_CODEC_FL32
, &input
);
184 msg_Err (obj
, "cannot find %s for conversion pipeline",
185 "pre-mix converter");
195 audio_sample_format_t output
;
196 output
.i_format
= input
.i_format
;
197 output
.i_rate
= input
.i_rate
;
198 output
.i_physical_channels
= outfmt
->i_physical_channels
;
199 output
.channel_type
= outfmt
->channel_type
;
200 output
.i_chan_mode
= outfmt
->i_chan_mode
;
201 aout_FormatPrepare (&output
);
203 const char *filter_type
=
204 infmt
->channel_type
!= outfmt
->channel_type
?
205 "audio renderer" : "audio converter";
207 config_chain_t
*cfg
= NULL
;
209 config_ChainParseOptions(&cfg
, "{headphones=true}");
210 filter_t
*f
= aout_filter_Create(obj
, NULL
, filter_type
, NULL
,
211 &input
, &output
, cfg
, true);
213 config_ChainDestroy(cfg
);
217 msg_Err (obj
, "cannot find %s for conversion pipeline",
227 if (input
.i_rate
!= outfmt
->i_rate
)
228 { /* Resampling works with any linear format, but may be ugly. */
232 audio_sample_format_t output
= input
;
233 output
.i_rate
= outfmt
->i_rate
;
235 filter_t
*f
= FindConverter (obj
, &input
, &output
);
238 msg_Err (obj
, "cannot find %s for conversion pipeline",
248 if (input
.i_format
!= outfmt
->i_format
)
253 filter_t
*f
= TryFormat (obj
, outfmt
->i_format
, &input
);
256 msg_Err (obj
, "cannot find %s for conversion pipeline",
257 "post-mix converter");
263 msg_Dbg (obj
, "conversion pipeline complete");
268 msg_Err (obj
, "maximum of %u conversion filters reached", max
);
269 vlc_dialog_display_error (obj
, _("Audio filtering failed"),
270 _("The maximum number of filters (%u) was reached."), max
);
272 aout_FiltersPipelineDestroy (filters
, n
);
277 * Filters an audio buffer through a chain of filters.
279 static block_t
*aout_FiltersPipelinePlay(filter_t
*const *filters
,
280 unsigned count
, block_t
*block
)
282 /* TODO: use filter chain */
283 for (unsigned i
= 0; (i
< count
) && (block
!= NULL
); i
++)
285 filter_t
*filter
= filters
[i
];
287 /* Please note that p_block->i_nb_samples & i_buffer
288 * shall be set by the filter plug-in. */
289 block
= filter
->pf_audio_filter (filter
, block
);
296 * Drain the chain of filters.
298 static block_t
*aout_FiltersPipelineDrain(filter_t
*const *filters
,
301 block_t
*chain
= NULL
;
303 for (unsigned i
= 0; i
< count
; i
++)
305 filter_t
*filter
= filters
[i
];
307 block_t
*block
= filter_DrainAudio (filter
);
310 /* If there is a drained block, filter it through the following
311 * chain of filters */
313 block
= aout_FiltersPipelinePlay (&filters
[i
+ 1],
314 count
- i
- 1, block
);
316 block_ChainAppend (&chain
, block
);
321 return block_ChainGather(chain
);
327 * Flush the chain of filters.
329 static void aout_FiltersPipelineFlush(filter_t
*const *filters
,
332 for (unsigned i
= 0; i
< count
; i
++)
333 filter_Flush (filters
[i
]);
336 static void aout_FiltersPipelineChangeViewpoint(filter_t
*const *filters
,
338 const vlc_viewpoint_t
*vp
)
340 for (unsigned i
= 0; i
< count
; i
++)
341 filter_ChangeViewpoint (filters
[i
], vp
);
344 #define AOUT_MAX_FILTERS 10
348 filter_t
*rate_filter
; /**< The filter adjusting samples count
349 (either the scaletempo filter or a resampler) */
350 filter_t
*resampler
; /**< The resampler */
351 int resampling
; /**< Current resampling (Hz) */
354 unsigned count
; /**< Number of filters */
355 filter_t
*tab
[AOUT_MAX_FILTERS
]; /**< Configured user filters
356 (e.g. equalization) and their conversions */
359 /** Callback for visualization selection */
360 static int VisualizationCallback (vlc_object_t
*obj
, const char *var
,
361 vlc_value_t oldval
, vlc_value_t newval
,
364 const char *mode
= newval
.psz_string
;
368 /* FIXME: This ugly hack enforced by visual effect-list, as is the need for
369 * separate "visual" (external) and "audio-visual" (internal) variables...
370 * The visual plugin should have one submodule per effect instead. */
371 if (strcasecmp (mode
, "none") && strcasecmp (mode
, "goom")
372 && strcasecmp (mode
, "projectm") && strcasecmp (mode
, "vsxu")
373 && strcasecmp (mode
, "glspectrum"))
375 var_Create (obj
, "effect-list", VLC_VAR_STRING
);
376 var_SetString (obj
, "effect-list", mode
);
380 var_SetString (obj
, "audio-visual", mode
);
381 aout_InputRequestRestart ((audio_output_t
*)obj
);
382 (void) var
; (void) oldval
; (void) data
;
386 vout_thread_t
*aout_filter_GetVout(filter_t
*filter
, const video_format_t
*fmt
)
388 vout_thread_t
*vout
= vout_Create(VLC_OBJECT(filter
));
389 if (unlikely(vout
== NULL
))
392 video_format_t adj_fmt
= *fmt
;
393 vout_configuration_t cfg
= {
394 .vout
= vout
, .clock
= filter
->owner
.sys
, .fmt
= &adj_fmt
,
397 video_format_AdjustColorSpace(&adj_fmt
);
399 if (vout_Request(&cfg
, NULL
, NULL
)) {
406 static int AppendFilter(vlc_object_t
*obj
, const char *type
, const char *name
,
407 aout_filters_t
*restrict filters
,
408 audio_sample_format_t
*restrict infmt
,
409 const audio_sample_format_t
*restrict outfmt
,
412 const unsigned max
= sizeof (filters
->tab
) / sizeof (filters
->tab
[0]);
413 if (filters
->count
>= max
)
415 msg_Err (obj
, "maximum of %u filters reached", max
);
419 const filter_owner_t owner
= { .sys
= filters
->clock
};
420 filter_t
*filter
= aout_filter_Create(obj
, &owner
, type
, name
,
421 infmt
, outfmt
, cfg
, false);
424 msg_Err (obj
, "cannot add user %s \"%s\" (skipped)", type
, name
);
428 /* convert to the filter input format if necessary */
429 if (aout_FiltersPipelineCreate (obj
, filters
->tab
, &filters
->count
,
430 max
- 1, infmt
, &filter
->fmt_in
.audio
, false))
432 msg_Err (filter
, "cannot add user %s \"%s\" (skipped)", type
, name
);
433 module_unneed (filter
, filter
->p_module
);
434 vlc_object_delete(filter
);
438 assert (filters
->count
< max
);
439 filters
->tab
[filters
->count
] = filter
;
441 *infmt
= filter
->fmt_out
.audio
;
445 static int AppendRemapFilter(vlc_object_t
*obj
, aout_filters_t
*restrict filters
,
446 audio_sample_format_t
*restrict infmt
,
447 const audio_sample_format_t
*restrict outfmt
,
448 const int *wg4_remap
)
453 /* The remap audio filter use a different order than wg4 */
454 static const uint8_t wg4_to_remap
[] = { 0, 2, 6, 7, 3, 5, 4, 1, 8 };
455 int remap
[AOUT_CHAN_MAX
];
457 for (int i
= 0; i
< AOUT_CHAN_MAX
; ++i
)
459 if (wg4_remap
[i
] != i
)
461 remap
[i
] = wg4_remap
[i
] >= 0 ? wg4_to_remap
[wg4_remap
[i
]] : -1;
467 int ret
= asprintf(&str
, "remap{channel-left=%d,channel-right=%d,"
468 "channel-middleleft=%d,channel-middleright=%d,"
469 "channel-rearleft=%d,channel-rearright=%d,"
470 "channel-rearcenter=%d,channel-center=%d,"
471 "channel-lfe=%d,normalize=false}",
472 remap
[0], remap
[1], remap
[2], remap
[3], remap
[4],
473 remap
[5], remap
[6], remap
[7], remap
[8]);
477 free(config_ChainCreate(&name
, &cfg
, str
));
478 if (name
!= NULL
&& cfg
!= NULL
)
479 ret
= AppendFilter(obj
, "audio filter", name
, filters
,
487 config_ChainDestroy(cfg
);
491 aout_filters_t
*aout_FiltersNewWithClock(vlc_object_t
*obj
, const vlc_clock_t
*clock
,
492 const audio_sample_format_t
*restrict infmt
,
493 const audio_sample_format_t
*restrict outfmt
,
494 const aout_filters_cfg_t
*cfg
)
496 aout_filters_t
*filters
= malloc (sizeof (*filters
));
497 if (unlikely(filters
== NULL
))
500 filters
->rate_filter
= NULL
;
501 filters
->resampler
= NULL
;
502 filters
->resampling
= 0;
506 filters
->clock
= vlc_clock_CreateSlave(clock
, AUDIO_ES
);
511 filters
->clock
= NULL
;
513 /* Prepare format structure */
514 aout_FormatPrint (obj
, "input", infmt
);
515 audio_sample_format_t input_format
= *infmt
;
516 audio_sample_format_t output_format
= *outfmt
;
518 /* Callbacks (before reading values and also before return statement) */
519 var_AddCallback (obj
, "visual", VisualizationCallback
, NULL
);
521 if (!AOUT_FMT_LINEAR(outfmt
))
522 { /* Non-linear output: just convert formats, no filters/visu */
523 if (!AOUT_FMTS_IDENTICAL(infmt
, outfmt
))
525 aout_FormatsPrint (obj
, "pass-through:", infmt
, outfmt
);
526 filters
->tab
[0] = FindConverter(obj
, infmt
, outfmt
);
527 if (filters
->tab
[0] == NULL
)
529 msg_Err (obj
, "cannot setup pass-through");
536 if (aout_FormatNbChannels(outfmt
) == 0)
538 msg_Warn (obj
, "No output channel mask, cannot setup filters");
542 assert(output_format
.channel_type
== AUDIO_CHANNEL_TYPE_BITMAP
);
543 if (input_format
.channel_type
!= output_format
.channel_type
)
545 /* Do the channel type conversion before any filters since audio
546 * converters and filters handle only AUDIO_CHANNEL_TYPE_BITMAP */
548 /* convert to the output format (minus resampling) if necessary */
549 output_format
.i_rate
= input_format
.i_rate
;
550 if (aout_FiltersPipelineCreate (obj
, filters
->tab
, &filters
->count
,
551 AOUT_MAX_FILTERS
, &input_format
, &output_format
,
554 msg_Warn (obj
, "cannot setup audio renderer pipeline");
555 /* Fallback to bitmap without any conversions */
556 input_format
.channel_type
= AUDIO_CHANNEL_TYPE_BITMAP
;
557 aout_FormatPrepare(&input_format
);
560 input_format
= output_format
;
563 if (aout_FormatNbChannels(&input_format
) == 0)
565 /* The input channel map is unknown, use the WAVE one and add a
566 * converter that will drop extra channels that are not handled by VLC
568 msg_Info(obj
, "unknown channel map, using the WAVE channel layout.");
570 assert(input_format
.i_channels
> 0);
571 audio_sample_format_t input_phys_format
= input_format
;
572 aout_SetWavePhysicalChannels(&input_phys_format
);
574 filter_t
*f
= FindConverter (obj
, &input_format
, &input_phys_format
);
577 msg_Err (obj
, "cannot find channel converter");
581 input_format
= input_phys_format
;
582 filters
->tab
[filters
->count
++] = f
;
585 assert(input_format
.channel_type
== AUDIO_CHANNEL_TYPE_BITMAP
);
587 /* parse user filter lists */
588 if (var_InheritBool (obj
, "audio-time-stretch"))
590 if (AppendFilter(obj
, "audio filter", "scaletempo",
591 filters
, &input_format
, &output_format
, NULL
) == 0)
592 filters
->rate_filter
= filters
->tab
[filters
->count
- 1];
597 AppendRemapFilter(obj
, filters
, &input_format
, &output_format
,
600 if (input_format
.i_channels
> 2 && cfg
->headphones
)
601 AppendFilter(obj
, "audio filter", "binauralizer", filters
,
602 &input_format
, &output_format
, NULL
);
605 /* Now add user filters */
606 char *str
= var_InheritString (obj
, "audio-filter");
609 char *p
= str
, *name
;
610 while ((name
= strsep (&p
, " :")) != NULL
)
612 AppendFilter(obj
, "audio filter", name
, filters
,
613 &input_format
, &output_format
, NULL
);
618 char *visual
= var_InheritString(obj
, "audio-visual");
619 if (visual
!= NULL
&& strcasecmp(visual
, "none"))
620 AppendFilter(obj
, "visualization", visual
, filters
,
621 &input_format
, &output_format
, NULL
);
624 /* convert to the output format (minus resampling) if necessary */
625 output_format
.i_rate
= input_format
.i_rate
;
626 if (aout_FiltersPipelineCreate (obj
, filters
->tab
, &filters
->count
,
627 AOUT_MAX_FILTERS
, &input_format
, &output_format
, false))
629 msg_Err (obj
, "cannot setup filtering pipeline");
632 input_format
= output_format
;
634 /* insert the resampler */
635 output_format
.i_rate
= outfmt
->i_rate
;
636 assert (AOUT_FMTS_IDENTICAL(&output_format
, outfmt
));
637 filters
->resampler
= FindResampler (obj
, &input_format
,
639 if (filters
->resampler
== NULL
&& input_format
.i_rate
!= outfmt
->i_rate
)
641 msg_Err (obj
, "cannot setup a resampler");
644 if (filters
->rate_filter
== NULL
)
645 filters
->rate_filter
= filters
->resampler
;
650 aout_FiltersPipelineDestroy (filters
->tab
, filters
->count
);
651 var_DelCallback(obj
, "visual", VisualizationCallback
, NULL
);
653 vlc_clock_Delete(filters
->clock
);
658 void aout_FiltersResetClock(aout_filters_t
*filters
)
660 assert(filters
->clock
);
661 vlc_clock_Reset(filters
->clock
);
664 void aout_FiltersSetClockDelay(aout_filters_t
*filters
, vlc_tick_t delay
)
666 assert(filters
->clock
);
667 vlc_clock_SetDelay(filters
->clock
, delay
);
670 #undef aout_FiltersNew
672 * Sets a chain of audio filters up.
673 * \param obj parent object for the filters
674 * \param infmt chain input format [IN]
675 * \param outfmt chain output format [IN]
676 * \param cfg a valid aout_filters_cfg_t struct or NULL.
677 * \return a filters chain or NULL on failure
679 aout_filters_t
*aout_FiltersNew(vlc_object_t
*obj
,
680 const audio_sample_format_t
*restrict infmt
,
681 const audio_sample_format_t
*restrict outfmt
,
682 const aout_filters_cfg_t
*cfg
)
684 return aout_FiltersNewWithClock(obj
, NULL
, infmt
, outfmt
, cfg
);
687 #undef aout_FiltersDelete
689 * Destroys a chain of audio filters.
690 * \param obj object used with aout_FiltersNew()
691 * \param filters chain to be destroyed
693 void aout_FiltersDelete (vlc_object_t
*obj
, aout_filters_t
*filters
)
695 if (filters
->resampler
!= NULL
)
696 aout_FiltersPipelineDestroy (&filters
->resampler
, 1);
697 aout_FiltersPipelineDestroy (filters
->tab
, filters
->count
);
698 var_DelCallback(obj
, "visual", VisualizationCallback
, NULL
);
700 vlc_clock_Delete(filters
->clock
);
704 bool aout_FiltersCanResample (aout_filters_t
*filters
)
706 return (filters
->resampler
!= NULL
);
709 bool aout_FiltersAdjustResampling (aout_filters_t
*filters
, int adjust
)
711 if (filters
->resampler
== NULL
)
715 filters
->resampling
+= adjust
;
717 filters
->resampling
= 0;
718 return filters
->resampling
!= 0;
721 block_t
*aout_FiltersPlay(aout_filters_t
*filters
, block_t
*block
, float rate
)
723 int nominal_rate
= 0;
727 filter_t
*rate_filter
= filters
->rate_filter
;
729 if (rate_filter
== NULL
)
730 goto drop
; /* Without linear, non-nominal rate is impossible. */
732 /* Override input rate */
733 nominal_rate
= rate_filter
->fmt_in
.audio
.i_rate
;
734 rate_filter
->fmt_in
.audio
.i_rate
= lroundf(nominal_rate
* rate
);
737 block
= aout_FiltersPipelinePlay (filters
->tab
, filters
->count
, block
);
738 if (filters
->resampler
!= NULL
)
739 { /* NOTE: the resampler needs to run even if resampling is 0.
740 * The decoder and output rates can still be different. */
741 filters
->resampler
->fmt_in
.audio
.i_rate
+= filters
->resampling
;
742 block
= aout_FiltersPipelinePlay (&filters
->resampler
, 1, block
);
743 filters
->resampler
->fmt_in
.audio
.i_rate
-= filters
->resampling
;
746 if (nominal_rate
!= 0)
747 { /* Restore input rate */
748 assert (filters
->rate_filter
!= NULL
);
749 filters
->rate_filter
->fmt_in
.audio
.i_rate
= nominal_rate
;
754 block_Release (block
);
758 block_t
*aout_FiltersDrain (aout_filters_t
*filters
)
760 /* Drain the filters pipeline */
761 block_t
*block
= aout_FiltersPipelineDrain (filters
->tab
, filters
->count
);
763 if (filters
->resampler
!= NULL
)
765 block_t
*chain
= NULL
;
767 filters
->resampler
->fmt_in
.audio
.i_rate
+= filters
->resampling
;
771 /* Resample the drained block from the filters pipeline */
772 block
= aout_FiltersPipelinePlay (&filters
->resampler
, 1, block
);
774 block_ChainAppend (&chain
, block
);
777 /* Drain the resampler filter */
778 block
= aout_FiltersPipelineDrain (&filters
->resampler
, 1);
780 block_ChainAppend (&chain
, block
);
782 filters
->resampler
->fmt_in
.audio
.i_rate
-= filters
->resampling
;
784 return chain
? block_ChainGather (chain
) : NULL
;
790 void aout_FiltersFlush (aout_filters_t
*filters
)
792 aout_FiltersPipelineFlush (filters
->tab
, filters
->count
);
794 if (filters
->resampler
!= NULL
)
795 aout_FiltersPipelineFlush (&filters
->resampler
, 1);
798 void aout_FiltersChangeViewpoint (aout_filters_t
*filters
,
799 const vlc_viewpoint_t
*vp
)
801 aout_FiltersPipelineChangeViewpoint (filters
->tab
, filters
->count
, vp
);