1 /*****************************************************************************
2 * mono.c : stereo2mono downmixsimple channel mixer plug-in
3 *****************************************************************************
4 * Copyright (C) 2006 M2X
7 * Authors: Jean-Paul Saman <jpsaman at m2x dot nl>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 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 General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
31 #include <math.h> /* sqrt */
32 #include <stdint.h> /* int16_t .. */
38 #include <vlc_common.h>
39 #include <vlc_plugin.h>
40 #include <vlc_block.h>
41 #include <vlc_filter.h>
44 /*****************************************************************************
46 *****************************************************************************/
47 static int OpenFilter ( vlc_object_t
* );
48 static void CloseFilter ( vlc_object_t
* );
50 static block_t
*Convert( filter_t
*p_filter
, block_t
*p_block
);
52 static unsigned int stereo_to_mono( aout_filter_t
*, aout_buffer_t
*,
54 static unsigned int mono( aout_filter_t
*, aout_buffer_t
*, aout_buffer_t
* );
55 static void stereo2mono_downmix( aout_filter_t
*, aout_buffer_t
*,
58 /*****************************************************************************
60 *****************************************************************************/
61 struct atomic_operation_t
63 int i_source_channel_offset
;
64 int i_dest_channel_offset
;
65 unsigned int i_delay
;/* in sample unit */
66 double d_amplitude_factor
;
73 unsigned int i_nb_channels
; /* number of int16_t per sample */
74 int i_channel_selected
;
77 size_t i_overflow_buffer_size
;/* in bytes */
78 uint8_t * p_overflow_buffer
;
79 unsigned int i_nb_atomic_operations
;
80 struct atomic_operation_t
* p_atomic_operations
;
83 #define MONO_DOWNMIX_TEXT N_("Use downmix algorithm")
84 #define MONO_DOWNMIX_LONGTEXT N_("This option selects a stereo to mono " \
85 "downmix algorithm that is used in the headphone channel mixer. It " \
86 "gives the effect of standing in a room full of speakers." )
88 #define MONO_CHANNEL_TEXT N_("Select channel to keep")
89 #define MONO_CHANNEL_LONGTEXT N_("This option silences all other channels " \
90 "except the selected channel. Choose one from (0=left, 1=right, " \
91 "2=rear left, 3=rear right, 4=center, 5=left front)")
93 static const int pi_pos_values
[] = { 0, 1, 2, 4, 8, 5 };
94 static const char *const ppsz_pos_descriptions
[] =
95 { N_("Left"), N_("Right"), N_("Left rear"), N_("Right rear"), N_("Center"),
98 /* our internal channel order (WG-4 order) */
99 static const uint32_t pi_channels_out
[] =
100 { AOUT_CHAN_LEFT
, AOUT_CHAN_RIGHT
, AOUT_CHAN_REARLEFT
, AOUT_CHAN_REARRIGHT
,
101 AOUT_CHAN_CENTER
, AOUT_CHAN_LFE
, 0 };
103 #define MONO_CFG "sout-mono-"
104 /*****************************************************************************
106 *****************************************************************************/
108 set_description( N_("Audio filter for stereo to mono conversion") )
109 set_capability( "audio filter", 2 )
110 set_category( CAT_AUDIO
)
111 set_subcategory( SUBCAT_AUDIO_AFILTER
)
112 set_callbacks( OpenFilter
, CloseFilter
)
113 set_shortname( "Mono" )
115 add_bool( MONO_CFG
"downmix", true, NULL
, MONO_DOWNMIX_TEXT
,
116 MONO_DOWNMIX_LONGTEXT
, false )
117 add_integer( MONO_CFG
"channel", -1, MONO_CHANNEL_TEXT
,
118 MONO_CHANNEL_LONGTEXT
, false )
119 change_integer_list( pi_pos_values
, ppsz_pos_descriptions
)
123 /* Init() and ComputeChannelOperations() -
124 * Code taken from modules/audio_filter/channel_mixer/headphone.c
125 * converted from float into int16_t based downmix
126 * Written by Boris Dorès <babal@via.ecp.fr>
129 /*****************************************************************************
130 * Init: initialize internal data structures
131 * and computes the needed atomic operations
132 *****************************************************************************/
133 /* x and z represent the coordinates of the virtual speaker
134 * relatively to the center of the listener's head, measured in meters :
143 * rear left rear right
147 static void ComputeChannelOperations( struct filter_sys_t
* p_data
,
148 unsigned int i_rate
, unsigned int i_next_atomic_operation
,
149 int i_source_channel_offset
, double d_x
, double d_z
,
150 double d_compensation_length
, double d_channel_amplitude_factor
)
152 double d_c
= 340; /*sound celerity (unit: m/s)*/
153 double d_compensation_delay
= (d_compensation_length
-0.1) / d_c
* i_rate
;
156 p_data
->p_atomic_operations
[i_next_atomic_operation
]
157 .i_source_channel_offset
= i_source_channel_offset
;
158 p_data
->p_atomic_operations
[i_next_atomic_operation
]
159 .i_dest_channel_offset
= 0;/* left */
160 p_data
->p_atomic_operations
[i_next_atomic_operation
]
161 .i_delay
= (int)( sqrt( (-0.1-d_x
)*(-0.1-d_x
) + (0-d_z
)*(0-d_z
) )
162 / d_c
* i_rate
- d_compensation_delay
);
165 p_data
->p_atomic_operations
[i_next_atomic_operation
]
166 .d_amplitude_factor
= d_channel_amplitude_factor
* 1.1 / 2;
170 p_data
->p_atomic_operations
[i_next_atomic_operation
]
171 .d_amplitude_factor
= d_channel_amplitude_factor
* 0.9 / 2;
175 p_data
->p_atomic_operations
[i_next_atomic_operation
]
176 .d_amplitude_factor
= d_channel_amplitude_factor
/ 2;
180 p_data
->p_atomic_operations
[i_next_atomic_operation
+ 1]
181 .i_source_channel_offset
= i_source_channel_offset
;
182 p_data
->p_atomic_operations
[i_next_atomic_operation
+ 1]
183 .i_dest_channel_offset
= 1;/* right */
184 p_data
->p_atomic_operations
[i_next_atomic_operation
+ 1]
185 .i_delay
= (int)( sqrt( (0.1-d_x
)*(0.1-d_x
) + (0-d_z
)*(0-d_z
) )
186 / d_c
* i_rate
- d_compensation_delay
);
189 p_data
->p_atomic_operations
[i_next_atomic_operation
+ 1]
190 .d_amplitude_factor
= d_channel_amplitude_factor
* 0.9 / 2;
194 p_data
->p_atomic_operations
[i_next_atomic_operation
+ 1]
195 .d_amplitude_factor
= d_channel_amplitude_factor
* 1.1 / 2;
199 p_data
->p_atomic_operations
[i_next_atomic_operation
+ 1]
200 .d_amplitude_factor
= d_channel_amplitude_factor
/ 2;
204 static int Init( vlc_object_t
*p_this
, struct filter_sys_t
* p_data
,
205 unsigned int i_nb_channels
, uint32_t i_physical_channels
,
206 unsigned int i_rate
)
208 double d_x
= var_InheritInteger( p_this
, "headphone-dim" );
210 double d_z_rear
= -d_x
/3;
212 unsigned int i_next_atomic_operation
;
213 int i_source_channel_offset
;
216 if( var_InheritBool( p_this
, "headphone-compensate" ) )
218 /* minimal distance to any speaker */
219 if( i_physical_channels
& AOUT_CHAN_REARCENTER
)
229 /* Number of elementary operations */
230 p_data
->i_nb_atomic_operations
= i_nb_channels
* 2;
231 if( i_physical_channels
& AOUT_CHAN_CENTER
)
233 p_data
->i_nb_atomic_operations
+= 2;
235 p_data
->p_atomic_operations
= malloc( sizeof(struct atomic_operation_t
)
236 * p_data
->i_nb_atomic_operations
);
237 if( p_data
->p_atomic_operations
== NULL
)
240 /* For each virtual speaker, computes elementary wave propagation time
242 i_next_atomic_operation
= 0;
243 i_source_channel_offset
= 0;
244 if( i_physical_channels
& AOUT_CHAN_LEFT
)
246 ComputeChannelOperations( p_data
, i_rate
247 , i_next_atomic_operation
, i_source_channel_offset
248 , -d_x
, d_z
, d_min
, 2.0 / i_nb_channels
);
249 i_next_atomic_operation
+= 2;
250 i_source_channel_offset
++;
252 if( i_physical_channels
& AOUT_CHAN_RIGHT
)
254 ComputeChannelOperations( p_data
, i_rate
255 , i_next_atomic_operation
, i_source_channel_offset
256 , d_x
, d_z
, d_min
, 2.0 / i_nb_channels
);
257 i_next_atomic_operation
+= 2;
258 i_source_channel_offset
++;
260 if( i_physical_channels
& AOUT_CHAN_MIDDLELEFT
)
262 ComputeChannelOperations( p_data
, i_rate
263 , i_next_atomic_operation
, i_source_channel_offset
264 , -d_x
, 0 , d_min
, 1.5 / i_nb_channels
);
265 i_next_atomic_operation
+= 2;
266 i_source_channel_offset
++;
268 if( i_physical_channels
& AOUT_CHAN_MIDDLERIGHT
)
270 ComputeChannelOperations( p_data
, i_rate
271 , i_next_atomic_operation
, i_source_channel_offset
272 , d_x
, 0 , d_min
, 1.5 / i_nb_channels
);
273 i_next_atomic_operation
+= 2;
274 i_source_channel_offset
++;
276 if( i_physical_channels
& AOUT_CHAN_REARLEFT
)
278 ComputeChannelOperations( p_data
, i_rate
279 , i_next_atomic_operation
, i_source_channel_offset
280 , -d_x
, d_z_rear
, d_min
, 1.5 / i_nb_channels
);
281 i_next_atomic_operation
+= 2;
282 i_source_channel_offset
++;
284 if( i_physical_channels
& AOUT_CHAN_REARRIGHT
)
286 ComputeChannelOperations( p_data
, i_rate
287 , i_next_atomic_operation
, i_source_channel_offset
288 , d_x
, d_z_rear
, d_min
, 1.5 / i_nb_channels
);
289 i_next_atomic_operation
+= 2;
290 i_source_channel_offset
++;
292 if( i_physical_channels
& AOUT_CHAN_REARCENTER
)
294 ComputeChannelOperations( p_data
, i_rate
295 , i_next_atomic_operation
, i_source_channel_offset
296 , 0 , -d_z
, d_min
, 1.5 / i_nb_channels
);
297 i_next_atomic_operation
+= 2;
298 i_source_channel_offset
++;
300 if( i_physical_channels
& AOUT_CHAN_CENTER
)
302 /* having two center channels increases the spatialization effect */
303 ComputeChannelOperations( p_data
, i_rate
304 , i_next_atomic_operation
, i_source_channel_offset
305 , d_x
/ 5.0 , d_z
, d_min
, 0.75 / i_nb_channels
);
306 i_next_atomic_operation
+= 2;
307 ComputeChannelOperations( p_data
, i_rate
308 , i_next_atomic_operation
, i_source_channel_offset
309 , -d_x
/ 5.0 , d_z
, d_min
, 0.75 / i_nb_channels
);
310 i_next_atomic_operation
+= 2;
311 i_source_channel_offset
++;
313 if( i_physical_channels
& AOUT_CHAN_LFE
)
315 ComputeChannelOperations( p_data
, i_rate
316 , i_next_atomic_operation
, i_source_channel_offset
317 , 0 , d_z_rear
, d_min
, 5.0 / i_nb_channels
);
318 i_next_atomic_operation
+= 2;
319 i_source_channel_offset
++;
322 /* Initialize the overflow buffer
323 * we need it because the process induce a delay in the samples */
324 p_data
->i_overflow_buffer_size
= 0;
325 for( i
= 0 ; i
< p_data
->i_nb_atomic_operations
; i
++ )
327 if( p_data
->i_overflow_buffer_size
328 < p_data
->p_atomic_operations
[i
].i_delay
* 2 * sizeof (int16_t) )
330 p_data
->i_overflow_buffer_size
331 = p_data
->p_atomic_operations
[i
].i_delay
* 2 * sizeof (int16_t);
334 p_data
->p_overflow_buffer
= malloc( p_data
->i_overflow_buffer_size
);
335 if( p_data
->p_overflow_buffer
== NULL
)
337 free( p_data
->p_atomic_operations
);
340 memset( p_data
->p_overflow_buffer
, 0, p_data
->i_overflow_buffer_size
);
346 /*****************************************************************************
348 *****************************************************************************/
349 static int OpenFilter( vlc_object_t
*p_this
)
351 filter_t
* p_filter
= (filter_t
*)p_this
;
352 filter_sys_t
*p_sys
= NULL
;
354 if( aout_FormatNbChannels( &(p_filter
->fmt_in
.audio
) ) == 1 )
356 /*msg_Dbg( p_filter, "filter discarded (incompatible format)" );*/
360 if( (p_filter
->fmt_in
.i_codec
!= VLC_CODEC_S16N
) ||
361 (p_filter
->fmt_out
.i_codec
!= VLC_CODEC_S16N
) )
363 /*msg_Err( p_this, "filter discarded (invalid format)" );*/
367 if( (p_filter
->fmt_in
.audio
.i_format
!= p_filter
->fmt_out
.audio
.i_format
) &&
368 (p_filter
->fmt_in
.audio
.i_rate
!= p_filter
->fmt_out
.audio
.i_rate
) &&
369 (p_filter
->fmt_in
.audio
.i_format
!= VLC_CODEC_S16N
) &&
370 (p_filter
->fmt_out
.audio
.i_format
!= VLC_CODEC_S16N
) &&
371 (p_filter
->fmt_in
.audio
.i_bitspersample
!=
372 p_filter
->fmt_out
.audio
.i_bitspersample
))
374 /*msg_Err( p_this, "couldn't load mono filter" );*/
378 /* Allocate the memory needed to store the module's structure */
379 p_sys
= p_filter
->p_sys
= malloc( sizeof(filter_sys_t
) );
383 p_sys
->b_downmix
= var_CreateGetBool( p_this
, MONO_CFG
"downmix" );
384 p_sys
->i_channel_selected
=
385 (unsigned int) var_CreateGetInteger( p_this
, MONO_CFG
"channel" );
387 if( p_sys
->b_downmix
)
389 msg_Dbg( p_this
, "using stereo to mono downmix" );
390 p_filter
->fmt_out
.audio
.i_physical_channels
= AOUT_CHAN_CENTER
;
391 p_filter
->fmt_out
.audio
.i_channels
= 1;
395 msg_Dbg( p_this
, "using pseudo mono" );
396 p_filter
->fmt_out
.audio
.i_physical_channels
=
397 (AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
);
398 p_filter
->fmt_out
.audio
.i_channels
= 2;
401 p_filter
->fmt_out
.audio
.i_rate
= p_filter
->fmt_in
.audio
.i_rate
;
402 p_filter
->fmt_out
.audio
.i_format
= p_filter
->fmt_out
.i_codec
;
404 p_sys
->i_nb_channels
= aout_FormatNbChannels( &(p_filter
->fmt_in
.audio
) );
405 p_sys
->i_bitspersample
= p_filter
->fmt_out
.audio
.i_bitspersample
;
407 p_sys
->i_overflow_buffer_size
= 0;
408 p_sys
->p_overflow_buffer
= NULL
;
409 p_sys
->i_nb_atomic_operations
= 0;
410 p_sys
->p_atomic_operations
= NULL
;
412 if( Init( VLC_OBJECT(p_filter
), p_filter
->p_sys
,
413 aout_FormatNbChannels( &p_filter
->fmt_in
.audio
),
414 p_filter
->fmt_in
.audio
.i_physical_channels
,
415 p_filter
->fmt_in
.audio
.i_rate
) < 0 )
417 var_Destroy( p_this
, MONO_CFG
"channel" );
418 var_Destroy( p_this
, MONO_CFG
"downmix" );
423 p_filter
->pf_audio_filter
= Convert
;
425 msg_Dbg( p_this
, "%4.4s->%4.4s, channels %d->%d, bits per sample: %i->%i",
426 (char *)&p_filter
->fmt_in
.i_codec
,
427 (char *)&p_filter
->fmt_out
.i_codec
,
428 p_filter
->fmt_in
.audio
.i_physical_channels
,
429 p_filter
->fmt_out
.audio
.i_physical_channels
,
430 p_filter
->fmt_in
.audio
.i_bitspersample
,
431 p_filter
->fmt_out
.audio
.i_bitspersample
);
436 /*****************************************************************************
438 *****************************************************************************/
439 static void CloseFilter( vlc_object_t
*p_this
)
441 filter_t
*p_filter
= (filter_t
*) p_this
;
442 filter_sys_t
*p_sys
= p_filter
->p_sys
;
444 var_Destroy( p_this
, MONO_CFG
"channel" );
445 var_Destroy( p_this
, MONO_CFG
"downmix" );
446 free( p_sys
->p_atomic_operations
);
447 free( p_sys
->p_overflow_buffer
);
451 /*****************************************************************************
453 *****************************************************************************/
454 static block_t
*Convert( filter_t
*p_filter
, block_t
*p_block
)
456 aout_filter_t aout_filter
;
457 aout_buffer_t in_buf
, out_buf
;
458 block_t
*p_out
= NULL
;
459 unsigned int i_samples
;
462 if( !p_block
|| !p_block
->i_nb_samples
)
465 block_Release( p_block
);
469 i_out_size
= p_block
->i_nb_samples
* p_filter
->p_sys
->i_bitspersample
/8 *
470 aout_FormatNbChannels( &(p_filter
->fmt_out
.audio
) );
472 p_out
= p_filter
->pf_audio_buffer_new( p_filter
, i_out_size
);
475 msg_Warn( p_filter
, "can't get output buffer" );
476 block_Release( p_block
);
479 p_out
->i_nb_samples
=
480 (p_block
->i_nb_samples
/ p_filter
->p_sys
->i_nb_channels
) *
481 aout_FormatNbChannels( &(p_filter
->fmt_out
.audio
) );
482 p_out
->i_dts
= p_block
->i_dts
;
483 p_out
->i_pts
= p_block
->i_pts
;
484 p_out
->i_length
= p_block
->i_length
;
486 aout_filter
.p_sys
= (struct aout_filter_sys_t
*)p_filter
->p_sys
;
487 aout_filter
.fmt_in
.audio
= p_filter
->fmt_in
.audio
;
488 aout_filter
.fmt_in
.audio
.i_format
= p_filter
->fmt_in
.i_codec
;
489 aout_filter
.fmt_out
.audio
= p_filter
->fmt_out
.audio
;
490 aout_filter
.fmt_out
.audio
.i_format
= p_filter
->fmt_out
.i_codec
;
492 in_buf
.p_buffer
= p_block
->p_buffer
;
493 in_buf
.i_buffer
= p_block
->i_buffer
;
494 in_buf
.i_nb_samples
= p_block
->i_nb_samples
;
497 unsigned int i_in_size
= in_buf
.i_nb_samples
* (p_filter
->p_sys
->i_bitspersample
/8) *
498 aout_FormatNbChannels( &(p_filter
->fmt_in
.audio
) );
499 if( (in_buf
.i_buffer
!= i_in_size
) && ((i_in_size
% 32) != 0) ) /* is it word aligned?? */
501 msg_Err( p_filter
, "input buffer is not word aligned" );
502 /* Fix output buffer to be word aligned */
506 out_buf
.p_buffer
= p_out
->p_buffer
;
507 out_buf
.i_buffer
= p_out
->i_buffer
;
508 out_buf
.i_nb_samples
= p_out
->i_nb_samples
;
510 memset( p_out
->p_buffer
, 0, i_out_size
);
511 if( p_filter
->p_sys
->b_downmix
)
513 stereo2mono_downmix( &aout_filter
, &in_buf
, &out_buf
);
514 i_samples
= mono( &aout_filter
, &out_buf
, &in_buf
);
518 i_samples
= stereo_to_mono( &aout_filter
, &out_buf
, &in_buf
);
521 p_out
->i_buffer
= out_buf
.i_buffer
;
522 p_out
->i_nb_samples
= out_buf
.i_nb_samples
;
524 block_Release( p_block
);
528 /* stereo2mono_downmix - stereo channels into one mono channel.
529 * Code taken from modules/audio_filter/channel_mixer/headphone.c
530 * converted from float into int16_t based downmix
531 * Written by Boris Dorès <babal@via.ecp.fr>
533 static void stereo2mono_downmix( aout_filter_t
* p_filter
,
534 aout_buffer_t
* p_in_buf
, aout_buffer_t
* p_out_buf
)
536 filter_sys_t
*p_sys
= (filter_sys_t
*)p_filter
->p_sys
;
538 int i_input_nb
= aout_FormatNbChannels( &p_filter
->fmt_in
.audio
);
539 int i_output_nb
= aout_FormatNbChannels( &p_filter
->fmt_out
.audio
);
541 int16_t * p_in
= (int16_t*) p_in_buf
->p_buffer
;
543 uint8_t * p_overflow
;
546 size_t i_overflow_size
; /* in bytes */
547 size_t i_out_size
; /* in bytes */
551 int i_source_channel_offset
;
552 int i_dest_channel_offset
;
553 unsigned int i_delay
;
554 double d_amplitude_factor
;
556 /* out buffer characterisitcs */
557 p_out_buf
->i_nb_samples
= p_in_buf
->i_nb_samples
;
558 p_out_buf
->i_buffer
= p_in_buf
->i_buffer
* i_output_nb
/ i_input_nb
;
559 p_out
= p_out_buf
->p_buffer
;
560 i_out_size
= p_out_buf
->i_buffer
;
562 /* Slide the overflow buffer */
563 p_overflow
= p_sys
->p_overflow_buffer
;
564 i_overflow_size
= p_sys
->i_overflow_buffer_size
;
566 if ( i_out_size
> i_overflow_size
)
567 memcpy( p_out
, p_overflow
, i_overflow_size
);
569 memcpy( p_out
, p_overflow
, i_out_size
);
571 p_slide
= p_sys
->p_overflow_buffer
;
572 while( p_slide
< p_overflow
+ i_overflow_size
)
574 if( p_slide
+ i_out_size
< p_overflow
+ i_overflow_size
)
576 memset( p_slide
, 0, i_out_size
);
577 if( p_slide
+ 2 * i_out_size
< p_overflow
+ i_overflow_size
)
578 memcpy( p_slide
, p_slide
+ i_out_size
, i_out_size
);
580 memcpy( p_slide
, p_slide
+ i_out_size
,
581 p_overflow
+ i_overflow_size
- ( p_slide
+ i_out_size
) );
585 memset( p_slide
, 0, p_overflow
+ i_overflow_size
- p_slide
);
587 p_slide
+= i_out_size
;
590 /* apply the atomic operations */
591 for( i
= 0; i
< p_sys
->i_nb_atomic_operations
; i
++ )
593 /* shorter variable names */
594 i_source_channel_offset
595 = p_sys
->p_atomic_operations
[i
].i_source_channel_offset
;
596 i_dest_channel_offset
597 = p_sys
->p_atomic_operations
[i
].i_dest_channel_offset
;
598 i_delay
= p_sys
->p_atomic_operations
[i
].i_delay
;
600 = p_sys
->p_atomic_operations
[i
].d_amplitude_factor
;
602 if( p_out_buf
->i_nb_samples
> i_delay
)
604 /* current buffer coefficients */
605 for( j
= 0; j
< p_out_buf
->i_nb_samples
- i_delay
; j
++ )
607 ((int16_t*)p_out
)[ (i_delay
+j
)*i_output_nb
+ i_dest_channel_offset
]
608 += p_in
[ j
* i_input_nb
+ i_source_channel_offset
]
609 * d_amplitude_factor
;
612 /* overflow buffer coefficients */
613 for( j
= 0; j
< i_delay
; j
++ )
615 ((int16_t*)p_overflow
)[ j
*i_output_nb
+ i_dest_channel_offset
]
616 += p_in
[ (p_out_buf
->i_nb_samples
- i_delay
+ j
)
617 * i_input_nb
+ i_source_channel_offset
]
618 * d_amplitude_factor
;
623 /* overflow buffer coefficients only */
624 for( j
= 0; j
< p_out_buf
->i_nb_samples
; j
++ )
626 ((int16_t*)p_overflow
)[ (i_delay
- p_out_buf
->i_nb_samples
+ j
)
627 * i_output_nb
+ i_dest_channel_offset
]
628 += p_in
[ j
* i_input_nb
+ i_source_channel_offset
]
629 * d_amplitude_factor
;
635 /* Simple stereo to mono mixing. */
636 static unsigned int mono( aout_filter_t
*p_filter
,
637 aout_buffer_t
*p_output
, aout_buffer_t
*p_input
)
639 filter_sys_t
*p_sys
= (filter_sys_t
*)p_filter
->p_sys
;
640 int16_t *p_in
, *p_out
;
641 unsigned int n
= 0, r
= 0;
643 p_in
= (int16_t *) p_input
->p_buffer
;
644 p_out
= (int16_t *) p_output
->p_buffer
;
646 while( n
< (p_input
->i_nb_samples
* p_sys
->i_nb_channels
) )
648 p_out
[r
] = (p_in
[n
] + p_in
[n
+1]) >> 1;
655 /* Simple stereo to mono mixing. */
656 static unsigned int stereo_to_mono( aout_filter_t
*p_filter
,
657 aout_buffer_t
*p_output
, aout_buffer_t
*p_input
)
659 filter_sys_t
*p_sys
= (filter_sys_t
*)p_filter
->p_sys
;
660 int16_t *p_in
, *p_out
;
663 p_in
= (int16_t *) p_input
->p_buffer
;
664 p_out
= (int16_t *) p_output
->p_buffer
;
666 for( n
= 0; n
< (p_input
->i_nb_samples
* p_sys
->i_nb_channels
); n
++ )
668 /* Fake real mono. */
669 if( p_sys
->i_channel_selected
== -1)
671 p_out
[n
] = p_out
[n
+1] = (p_in
[n
] + p_in
[n
+1]) >> 1;
674 else if( (n
% p_sys
->i_nb_channels
) == (unsigned int) p_sys
->i_channel_selected
)
676 p_out
[n
] = p_out
[n
+1] = p_in
[n
];