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 .. */
34 #define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_block.h>
38 #include <vlc_filter.h>
41 /*****************************************************************************
43 *****************************************************************************/
44 static int OpenFilter ( vlc_object_t * );
45 static void CloseFilter ( vlc_object_t * );
47 static block_t *Convert( filter_t *p_filter, block_t *p_block );
49 static unsigned int stereo_to_mono( filter_t *, block_t *, block_t * );
50 static unsigned int mono( filter_t *, block_t *, block_t * );
51 static void stereo2mono_downmix( filter_t *, block_t *, block_t * );
53 /*****************************************************************************
55 *****************************************************************************/
56 struct atomic_operation_t
58 int i_source_channel_offset;
59 int i_dest_channel_offset;
60 unsigned int i_delay;/* in sample unit */
61 double d_amplitude_factor;
68 unsigned int i_nb_channels; /* number of int16_t per sample */
69 int i_channel_selected;
72 size_t i_overflow_buffer_size;/* in bytes */
73 uint8_t * p_overflow_buffer;
74 unsigned int i_nb_atomic_operations;
75 struct atomic_operation_t * p_atomic_operations;
78 #define MONO_DOWNMIX_TEXT N_("Use downmix algorithm")
79 #define MONO_DOWNMIX_LONGTEXT N_("This option selects a stereo to mono " \
80 "downmix algorithm that is used in the headphone channel mixer. It " \
81 "gives the effect of standing in a room full of speakers." )
83 #define MONO_CHANNEL_TEXT N_("Select channel to keep")
84 #define MONO_CHANNEL_LONGTEXT N_("This option silences all other channels " \
85 "except the selected channel.")
87 static const int pi_pos_values[] = { 0, 1, 4, 5, 7, 8, 2, 3, 6 };
88 static const char *const ppsz_pos_descriptions[] =
89 { N_("Left"), N_("Right"),
90 N_("Rear left"), N_("Rear right"),
91 N_("Center"), N_("Low-frequency effects"),
92 N_("Side left"), N_("Side right"), N_("Rear center") };
94 #define MONO_CFG "sout-mono-"
95 /*****************************************************************************
97 *****************************************************************************/
99 set_description( N_("Stereo to mono downmixer") )
100 set_capability( "audio filter", 0 )
101 set_category( CAT_AUDIO )
102 set_subcategory( SUBCAT_AUDIO_AFILTER )
103 set_callbacks( OpenFilter, CloseFilter )
104 set_shortname( "Mono" )
106 add_bool( MONO_CFG "downmix", true, MONO_DOWNMIX_TEXT,
107 MONO_DOWNMIX_LONGTEXT, false )
108 add_integer( MONO_CFG "channel", -1, MONO_CHANNEL_TEXT,
109 MONO_CHANNEL_LONGTEXT, false )
110 change_integer_list( pi_pos_values, ppsz_pos_descriptions )
114 /* Init() and ComputeChannelOperations() -
115 * Code taken from modules/audio_filter/channel_mixer/headphone.c
116 * converted from float into int16_t based downmix
117 * Written by Boris Dorès <babal@via.ecp.fr>
120 /*****************************************************************************
121 * Init: initialize internal data structures
122 * and computes the needed atomic operations
123 *****************************************************************************/
124 /* x and z represent the coordinates of the virtual speaker
125 * relatively to the center of the listener's head, measured in meters :
134 * rear left rear right
138 static void ComputeChannelOperations( struct filter_sys_t * p_data,
139 unsigned int i_rate, unsigned int i_next_atomic_operation,
140 int i_source_channel_offset, double d_x, double d_z,
141 double d_compensation_length, double d_channel_amplitude_factor )
143 double d_c = 340; /*sound celerity (unit: m/s)*/
144 double d_compensation_delay = (d_compensation_length-0.1) / d_c * i_rate;
147 p_data->p_atomic_operations[i_next_atomic_operation]
148 .i_source_channel_offset = i_source_channel_offset;
149 p_data->p_atomic_operations[i_next_atomic_operation]
150 .i_dest_channel_offset = 0;/* left */
151 p_data->p_atomic_operations[i_next_atomic_operation]
152 .i_delay = (int)( sqrt( (-0.1-d_x)*(-0.1-d_x) + (0-d_z)*(0-d_z) )
153 / d_c * i_rate - d_compensation_delay );
156 p_data->p_atomic_operations[i_next_atomic_operation]
157 .d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2;
161 p_data->p_atomic_operations[i_next_atomic_operation]
162 .d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2;
166 p_data->p_atomic_operations[i_next_atomic_operation]
167 .d_amplitude_factor = d_channel_amplitude_factor / 2;
171 p_data->p_atomic_operations[i_next_atomic_operation + 1]
172 .i_source_channel_offset = i_source_channel_offset;
173 p_data->p_atomic_operations[i_next_atomic_operation + 1]
174 .i_dest_channel_offset = 1;/* right */
175 p_data->p_atomic_operations[i_next_atomic_operation + 1]
176 .i_delay = (int)( sqrt( (0.1-d_x)*(0.1-d_x) + (0-d_z)*(0-d_z) )
177 / d_c * i_rate - d_compensation_delay );
180 p_data->p_atomic_operations[i_next_atomic_operation + 1]
181 .d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2;
185 p_data->p_atomic_operations[i_next_atomic_operation + 1]
186 .d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2;
190 p_data->p_atomic_operations[i_next_atomic_operation + 1]
191 .d_amplitude_factor = d_channel_amplitude_factor / 2;
195 static int Init( vlc_object_t *p_this, struct filter_sys_t * p_data,
196 unsigned int i_nb_channels, uint32_t i_physical_channels,
197 unsigned int i_rate )
199 double d_x = var_InheritInteger( p_this, "headphone-dim" );
201 double d_z_rear = -d_x/3;
203 unsigned int i_next_atomic_operation;
204 int i_source_channel_offset;
207 if( var_InheritBool( p_this, "headphone-compensate" ) )
209 /* minimal distance to any speaker */
210 if( i_physical_channels & AOUT_CHAN_REARCENTER )
220 /* Number of elementary operations */
221 p_data->i_nb_atomic_operations = i_nb_channels * 2;
222 if( i_physical_channels & AOUT_CHAN_CENTER )
224 p_data->i_nb_atomic_operations += 2;
226 p_data->p_atomic_operations = malloc( sizeof(struct atomic_operation_t)
227 * p_data->i_nb_atomic_operations );
228 if( p_data->p_atomic_operations == NULL )
231 /* For each virtual speaker, computes elementary wave propagation time
233 i_next_atomic_operation = 0;
234 i_source_channel_offset = 0;
235 if( i_physical_channels & AOUT_CHAN_LEFT )
237 ComputeChannelOperations( p_data , i_rate
238 , i_next_atomic_operation , i_source_channel_offset
239 , -d_x , d_z , d_min , 2.0 / i_nb_channels );
240 i_next_atomic_operation += 2;
241 i_source_channel_offset++;
243 if( i_physical_channels & AOUT_CHAN_RIGHT )
245 ComputeChannelOperations( p_data , i_rate
246 , i_next_atomic_operation , i_source_channel_offset
247 , d_x , d_z , d_min , 2.0 / i_nb_channels );
248 i_next_atomic_operation += 2;
249 i_source_channel_offset++;
251 if( i_physical_channels & AOUT_CHAN_MIDDLELEFT )
253 ComputeChannelOperations( p_data , i_rate
254 , i_next_atomic_operation , i_source_channel_offset
255 , -d_x , 0 , d_min , 1.5 / i_nb_channels );
256 i_next_atomic_operation += 2;
257 i_source_channel_offset++;
259 if( i_physical_channels & AOUT_CHAN_MIDDLERIGHT )
261 ComputeChannelOperations( p_data , i_rate
262 , i_next_atomic_operation , i_source_channel_offset
263 , d_x , 0 , d_min , 1.5 / i_nb_channels );
264 i_next_atomic_operation += 2;
265 i_source_channel_offset++;
267 if( i_physical_channels & AOUT_CHAN_REARLEFT )
269 ComputeChannelOperations( p_data , i_rate
270 , i_next_atomic_operation , i_source_channel_offset
271 , -d_x , d_z_rear , d_min , 1.5 / i_nb_channels );
272 i_next_atomic_operation += 2;
273 i_source_channel_offset++;
275 if( i_physical_channels & AOUT_CHAN_REARRIGHT )
277 ComputeChannelOperations( p_data , i_rate
278 , i_next_atomic_operation , i_source_channel_offset
279 , d_x , d_z_rear , d_min , 1.5 / i_nb_channels );
280 i_next_atomic_operation += 2;
281 i_source_channel_offset++;
283 if( i_physical_channels & AOUT_CHAN_REARCENTER )
285 ComputeChannelOperations( p_data , i_rate
286 , i_next_atomic_operation , i_source_channel_offset
287 , 0 , -d_z , d_min , 1.5 / i_nb_channels );
288 i_next_atomic_operation += 2;
289 i_source_channel_offset++;
291 if( i_physical_channels & AOUT_CHAN_CENTER )
293 /* having two center channels increases the spatialization effect */
294 ComputeChannelOperations( p_data , i_rate
295 , i_next_atomic_operation , i_source_channel_offset
296 , d_x / 5.0 , d_z , d_min , 0.75 / i_nb_channels );
297 i_next_atomic_operation += 2;
298 ComputeChannelOperations( p_data , i_rate
299 , i_next_atomic_operation , i_source_channel_offset
300 , -d_x / 5.0 , d_z , d_min , 0.75 / i_nb_channels );
301 i_next_atomic_operation += 2;
302 i_source_channel_offset++;
304 if( i_physical_channels & AOUT_CHAN_LFE )
306 ComputeChannelOperations( p_data , i_rate
307 , i_next_atomic_operation , i_source_channel_offset
308 , 0 , d_z_rear , d_min , 5.0 / i_nb_channels );
309 i_next_atomic_operation += 2;
310 i_source_channel_offset++;
313 /* Initialize the overflow buffer
314 * we need it because the process induce a delay in the samples */
315 p_data->i_overflow_buffer_size = 0;
316 for( i = 0 ; i < p_data->i_nb_atomic_operations ; i++ )
318 if( p_data->i_overflow_buffer_size
319 < p_data->p_atomic_operations[i].i_delay * 2 * sizeof (int16_t) )
321 p_data->i_overflow_buffer_size
322 = p_data->p_atomic_operations[i].i_delay * 2 * sizeof (int16_t);
325 p_data->p_overflow_buffer = malloc( p_data->i_overflow_buffer_size );
326 if( p_data->p_overflow_buffer == NULL )
328 free( p_data->p_atomic_operations );
331 memset( p_data->p_overflow_buffer, 0, p_data->i_overflow_buffer_size );
337 /*****************************************************************************
339 *****************************************************************************/
340 static int OpenFilter( vlc_object_t *p_this )
342 filter_t * p_filter = (filter_t *)p_this;
343 filter_sys_t *p_sys = NULL;
345 if( aout_FormatNbChannels( &(p_filter->fmt_in.audio) ) == 1 )
347 /*msg_Dbg( p_filter, "filter discarded (incompatible format)" );*/
351 p_filter->fmt_in.audio.i_format = VLC_CODEC_S16N;
352 p_filter->fmt_out.audio.i_format = VLC_CODEC_S16N;
354 /* Allocate the memory needed to store the module's structure */
355 p_sys = p_filter->p_sys = malloc( sizeof(filter_sys_t) );
359 p_sys->b_downmix = var_InheritBool( p_this, MONO_CFG "downmix" );
360 p_sys->i_channel_selected = var_InheritInteger( p_this, MONO_CFG "channel" );
362 p_sys->i_nb_channels = aout_FormatNbChannels( &(p_filter->fmt_in.audio) );
363 p_sys->i_bitspersample = p_filter->fmt_out.audio.i_bitspersample;
365 p_sys->i_overflow_buffer_size = 0;
366 p_sys->p_overflow_buffer = NULL;
367 p_sys->i_nb_atomic_operations = 0;
368 p_sys->p_atomic_operations = NULL;
370 if( Init( VLC_OBJECT(p_filter), p_filter->p_sys,
371 aout_FormatNbChannels( &p_filter->fmt_in.audio ),
372 p_filter->fmt_in.audio.i_physical_channels,
373 p_filter->fmt_in.audio.i_rate ) < 0 )
379 if( p_sys->b_downmix )
381 msg_Dbg( p_this, "using stereo to mono downmix" );
382 p_filter->fmt_out.audio.i_physical_channels = AOUT_CHAN_CENTER;
383 p_filter->fmt_out.audio.i_channels = 1;
387 msg_Dbg( p_this, "using pseudo mono" );
388 p_filter->fmt_out.audio.i_physical_channels = AOUT_CHANS_STEREO;
389 p_filter->fmt_out.audio.i_channels = 2;
391 p_filter->fmt_out.audio.i_rate = p_filter->fmt_in.audio.i_rate;
392 p_filter->pf_audio_filter = Convert;
394 msg_Dbg( p_this, "%4.4s->%4.4s, channels %d->%d, bits per sample: %i->%i",
395 (char *)&p_filter->fmt_in.i_codec,
396 (char *)&p_filter->fmt_out.i_codec,
397 p_filter->fmt_in.audio.i_physical_channels,
398 p_filter->fmt_out.audio.i_physical_channels,
399 p_filter->fmt_in.audio.i_bitspersample,
400 p_filter->fmt_out.audio.i_bitspersample );
405 /*****************************************************************************
407 *****************************************************************************/
408 static void CloseFilter( vlc_object_t *p_this)
410 filter_t *p_filter = (filter_t *) p_this;
411 filter_sys_t *p_sys = p_filter->p_sys;
413 free( p_sys->p_atomic_operations );
414 free( p_sys->p_overflow_buffer );
418 /*****************************************************************************
420 *****************************************************************************/
421 static block_t *Convert( filter_t *p_filter, block_t *p_block )
426 if( !p_block || !p_block->i_nb_samples )
429 block_Release( p_block );
433 i_out_size = p_block->i_nb_samples * p_filter->p_sys->i_bitspersample/8 *
434 aout_FormatNbChannels( &(p_filter->fmt_out.audio) );
436 p_out = block_Alloc( i_out_size );
439 msg_Warn( p_filter, "can't get output buffer" );
440 block_Release( p_block );
443 p_out->i_nb_samples =
444 (p_block->i_nb_samples / p_filter->p_sys->i_nb_channels) *
445 aout_FormatNbChannels( &(p_filter->fmt_out.audio) );
448 unsigned int i_in_size = in_buf.i_nb_samples * (p_filter->p_sys->i_bitspersample/8) *
449 aout_FormatNbChannels( &(p_filter->fmt_in.audio) );
450 if( (in_buf.i_buffer != i_in_size) && ((i_in_size % 32) != 0) ) /* is it word aligned?? */
452 msg_Err( p_filter, "input buffer is not word aligned" );
453 /* Fix output buffer to be word aligned */
457 memset( p_out->p_buffer, 0, i_out_size );
458 if( p_filter->p_sys->b_downmix )
460 stereo2mono_downmix( p_filter, p_block, p_out );
461 mono( p_filter, p_out, p_block );
465 stereo_to_mono( p_filter, p_out, p_block );
468 block_Release( p_block );
472 /* stereo2mono_downmix - stereo channels into one mono channel.
473 * Code taken from modules/audio_filter/channel_mixer/headphone.c
474 * converted from float into int16_t based downmix
475 * Written by Boris Dorès <babal@via.ecp.fr>
477 static void stereo2mono_downmix( filter_t * p_filter,
478 block_t * p_in_buf, block_t * p_out_buf )
480 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
482 int i_input_nb = aout_FormatNbChannels( &p_filter->fmt_in.audio );
483 int i_output_nb = aout_FormatNbChannels( &p_filter->fmt_out.audio );
485 int16_t * p_in = (int16_t*) p_in_buf->p_buffer;
487 uint8_t * p_overflow;
490 size_t i_overflow_size; /* in bytes */
491 size_t i_out_size; /* in bytes */
495 int i_source_channel_offset;
496 int i_dest_channel_offset;
497 unsigned int i_delay;
498 double d_amplitude_factor;
500 /* out buffer characterisitcs */
501 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
502 p_out_buf->i_buffer = p_in_buf->i_buffer * i_output_nb / i_input_nb;
503 p_out = p_out_buf->p_buffer;
504 i_out_size = p_out_buf->i_buffer;
506 /* Slide the overflow buffer */
507 p_overflow = p_sys->p_overflow_buffer;
508 i_overflow_size = p_sys->i_overflow_buffer_size;
510 if ( i_out_size > i_overflow_size )
511 memcpy( p_out, p_overflow, i_overflow_size );
513 memcpy( p_out, p_overflow, i_out_size );
515 p_slide = p_sys->p_overflow_buffer;
516 while( p_slide < p_overflow + i_overflow_size )
518 if( p_slide + i_out_size < p_overflow + i_overflow_size )
520 memset( p_slide, 0, i_out_size );
521 if( p_slide + 2 * i_out_size < p_overflow + i_overflow_size )
522 memcpy( p_slide, p_slide + i_out_size, i_out_size );
524 memcpy( p_slide, p_slide + i_out_size,
525 p_overflow + i_overflow_size - ( p_slide + i_out_size ) );
529 memset( p_slide, 0, p_overflow + i_overflow_size - p_slide );
531 p_slide += i_out_size;
534 /* apply the atomic operations */
535 for( i = 0; i < p_sys->i_nb_atomic_operations; i++ )
537 /* shorter variable names */
538 i_source_channel_offset
539 = p_sys->p_atomic_operations[i].i_source_channel_offset;
540 i_dest_channel_offset
541 = p_sys->p_atomic_operations[i].i_dest_channel_offset;
542 i_delay = p_sys->p_atomic_operations[i].i_delay;
544 = p_sys->p_atomic_operations[i].d_amplitude_factor;
546 if( p_out_buf->i_nb_samples > i_delay )
548 /* current buffer coefficients */
549 for( j = 0; j < p_out_buf->i_nb_samples - i_delay; j++ )
551 ((int16_t*)p_out)[ (i_delay+j)*i_output_nb + i_dest_channel_offset ]
552 += p_in[ j * i_input_nb + i_source_channel_offset ]
553 * d_amplitude_factor;
556 /* overflow buffer coefficients */
557 for( j = 0; j < i_delay; j++ )
559 ((int16_t*)p_overflow)[ j*i_output_nb + i_dest_channel_offset ]
560 += p_in[ (p_out_buf->i_nb_samples - i_delay + j)
561 * i_input_nb + i_source_channel_offset ]
562 * d_amplitude_factor;
567 /* overflow buffer coefficients only */
568 for( j = 0; j < p_out_buf->i_nb_samples; j++ )
570 ((int16_t*)p_overflow)[ (i_delay - p_out_buf->i_nb_samples + j)
571 * i_output_nb + i_dest_channel_offset ]
572 += p_in[ j * i_input_nb + i_source_channel_offset ]
573 * d_amplitude_factor;
579 /* Simple stereo to mono mixing. */
580 static unsigned int mono( filter_t *p_filter,
581 block_t *p_output, block_t *p_input )
583 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
584 int16_t *p_in, *p_out;
585 unsigned int n = 0, r = 0;
587 p_in = (int16_t *) p_input->p_buffer;
588 p_out = (int16_t *) p_output->p_buffer;
590 while( n < (p_input->i_nb_samples * p_sys->i_nb_channels) )
592 p_out[r] = (p_in[n] + p_in[n+1]) >> 1;
599 /* Simple stereo to mono mixing. */
600 static unsigned int stereo_to_mono( filter_t *p_filter,
601 block_t *p_output, block_t *p_input )
603 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
604 int16_t *p_in, *p_out;
607 p_in = (int16_t *) p_input->p_buffer;
608 p_out = (int16_t *) p_output->p_buffer;
610 for( n = 0; n < (p_input->i_nb_samples * p_sys->i_nb_channels); n++ )
612 /* Fake real mono. */
613 if( p_sys->i_channel_selected == -1)
615 p_out[n] = p_out[n+1] = (p_in[n] + p_in[n+1]) >> 1;
618 else if( (n % p_sys->i_nb_channels) == (unsigned int) p_sys->i_channel_selected )
620 p_out[n] = p_out[n+1] = p_in[n];